Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

Add simple basic Tagging module #10

Merged
merged 6 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions contracts/lib/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,15 @@ library Errors {
error AccessController__SignerIsZeroAddress();
error AccessController__CallerIsNotIPAccount();
error AccessController__PermissionIsNotValid();

////////////////////////////////////////////////////////////////////////////
// TaggingModule //
////////////////////////////////////////////////////////////////////////////

error TaggingModule__InvalidRelationTypeName();
error TaggingModule__RelationTypeAlreadyExists();
error TaggingModule__SrcIpIdDoesNotHaveSrcTag();
error TaggingModule__DstIpIdDoesNotHaveDstTag();
error TaggingModule__RelationTypeDoesNotExist();

}
4 changes: 2 additions & 2 deletions contracts/modules/dispute-module/DisputeModule.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

import {ShortStringEquals} from "../../utils/ShortStringOps.sol";
import {ShortStringOps} from "../../utils/ShortStringOps.sol";
import {IArbitrationPolicy} from "../../../interfaces/modules/dispute-module/policies/IArbitrationPolicy.sol";
import {IDisputeModule} from "../../../interfaces/modules/dispute-module/IDisputeModule.sol";

Expand Down Expand Up @@ -102,7 +102,7 @@ contract DisputeModule is IDisputeModule, ReentrancyGuard {
}
if (!isWhitelistedDisputeTag[_targetTag]) revert Errors.DisputeModule__NotWhitelistedDisputeTag();

bytes32 linkToDisputeSummary = ShortStringEquals.stringToBytes32(_linkToDisputeSummary);
bytes32 linkToDisputeSummary = ShortStringOps.stringToBytes32(_linkToDisputeSummary);
if (linkToDisputeSummary == bytes32(0)) revert Errors.DisputeModule__ZeroLinkToDisputeSummary();

disputeId++;
Expand Down
52 changes: 52 additions & 0 deletions contracts/modules/tagging/TaggingModule.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: UNLICENSED
// See https://github.com/storyprotocol/protocol-contracts/blob/main/StoryProtocol-AlphaTestingAgreement-17942166.3.pdf

pragma solidity ^0.8.21;

import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";
import { ShortStringOps } from "contracts/utils/ShortStringOps.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { Errors } from "contracts/lib/Errors.sol";
import { IModule } from "contracts/interfaces/modules/base/IModule.sol";

contract TaggingModule is IModule {
using ShortStrings for *;
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;

uint256 constant MAX_TAG_PERMISSIONS_AT_ONCE = 300;

string public name = "TaggingModule";

mapping(address => EnumerableSet.Bytes32Set) private _tagsForIpIds;

function setTag(string calldata tag, address ipId) external returns (bool added) {
// TODO: access control
kingster-will marked this conversation as resolved.
Show resolved Hide resolved
// TODO: emit
return _tagsForIpIds[ipId].add(ShortStringOps.stringToBytes32(tag));
}

function removeTag(string calldata tag, address ipId) external returns (bool removed) {
// TODO: access control
kingster-will marked this conversation as resolved.
Show resolved Hide resolved
return _tagsForIpIds[ipId].remove(ShortStringOps.stringToBytes32(tag));
}

function isTagged(string calldata tag, address ipId) external view returns (bool) {
return _tagsForIpIds[ipId].contains(ShortStringOps.stringToBytes32(tag));
}

function totalTagsForIp(address ipId) external view returns (uint256) {
return _tagsForIpIds[ipId].length();
}

function tagAtIndexForIp(address ipId, uint256 index) external view returns (bytes32) {
// WARNING: tag ordering not guaranteed (since they can be removed)
return _tagsForIpIds[ipId].at(index);
}

function tagStringAtIndexForIp(address ipId, uint256 index) external view returns (string memory) {
// WARNING: tag ordering not guaranteed (since they can be removed)
return ShortString.wrap(_tagsForIpIds[ipId].at(index)).toString();
}

}
2 changes: 1 addition & 1 deletion contracts/utils/ShortStringOps.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity ^0.8.19;
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";

/// @notice Library for working with Openzeppelin's ShortString data types.
library ShortStringEquals {
library ShortStringOps {
using ShortStrings for *;

/// @dev Compares whether two ShortStrings are equal.
Expand Down
4 changes: 2 additions & 2 deletions test/foundry/DisputeModule.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.23;
import {console2} from "forge-std/console2.sol";
import {TestHelper} from "./../utils/TestHelper.sol";

import {ShortStringEquals} from "./../../contracts/utils/ShortStringOps.sol";
import {ShortStringOps} from "./../../contracts/utils/ShortStringOps.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract TestDisputeModule is TestHelper {
Expand Down Expand Up @@ -65,7 +65,7 @@ contract TestDisputeModule is TestHelper {
assertEq(ip_id, address(1));
assertEq(disputeInitiator, ipAccount1);
assertEq(arbitrationPolicy, address(arbitrationPolicySP));
assertEq(linkToDisputeSummary, ShortStringEquals.stringToBytes32("urlExample"));
assertEq(linkToDisputeSummary, ShortStringOps.stringToBytes32("urlExample"));
assertEq(tag, bytes32("plagiarism"));
}

Expand Down
58 changes: 58 additions & 0 deletions test/foundry/modules/TaggingModule.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "forge-std/Test.sol";
import "contracts/lib/Errors.sol";
import { TaggingModule } from "contracts/modules/tagging/TaggingModule.sol";
import { ShortStringOps } from "contracts/utils/ShortStringOps.sol";
import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortStrings.sol";

contract TaggingModuleTest is Test {
using ShortStrings for *;
TaggingModule public taggingModule;

function setUp() public {
taggingModule = new TaggingModule();
}

function test_taggingModule_setTag() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
}

function test_taggingModule_removeTag() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
assertEq(taggingModule.removeTag("test", ipAccount), true);
}

function test_taggingModule_isTagged() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
assertEq(taggingModule.isTagged("test", ipAccount), true);
}

function test_taggingModule_totalTagsForIP() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
assertEq(taggingModule.setTag("test-1", ipAccount), true);
assertEq(taggingModule.setTag("test-2", ipAccount), true);
assertEq(taggingModule.totalTagsForIp(ipAccount), 3);
}

function test_taggingModule_tagAtIndexForIp() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
assertEq(taggingModule.setTag("test-1", ipAccount), true);
assertEq(taggingModule.setTag("test-2", ipAccount), true);
assertEq(taggingModule.tagAtIndexForIp(ipAccount, 2), ShortStringOps.stringToBytes32("test-2"));
}

function test_taggingModule_tagStringAtIndexForIp() public {
address ipAccount = address(1);
assertEq(taggingModule.setTag("test", ipAccount), true);
assertEq(taggingModule.setTag("test-1", ipAccount), true);
assertEq(taggingModule.setTag("test-2", ipAccount), true);
assertEq(taggingModule.tagStringAtIndexForIp(ipAccount, 2), "test-2");
}
}