Skip to content

Commit 3faa9d3

Browse files
authored
Transfer validator has roles (#143)
* created hasRole function in the roylaty module * created tests
1 parent 03da7c2 commit 3faa9d3

File tree

4 files changed

+222
-18
lines changed

4 files changed

+222
-18
lines changed

src/module/token/royalty/RoyaltyERC1155.sol

+27-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
44
import {Module} from "../../../Module.sol";
55

66
import {Role} from "../../../Role.sol";
7+
import {OwnableRoles} from "@solady/auth/OwnableRoles.sol";
78

89
import {BeforeBatchTransferCallbackERC1155} from "../../../callback/BeforeBatchTransferCallbackERC1155.sol";
910
import {BeforeTransferCallbackERC1155} from "../../../callback/BeforeTransferCallbackERC1155.sol";
@@ -47,6 +48,12 @@ contract RoyaltyERC1155 is
4748
BeforeBatchTransferCallbackERC1155
4849
{
4950

51+
/*//////////////////////////////////////////////////////////////
52+
CONSTANTS
53+
//////////////////////////////////////////////////////////////*/
54+
55+
bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
56+
5057
/*//////////////////////////////////////////////////////////////
5158
STRUCTS
5259
//////////////////////////////////////////////////////////////*/
@@ -82,7 +89,10 @@ contract RoyaltyERC1155 is
8289
error RoyaltyExceedsMaxBps();
8390

8491
/// @notice Revert with an error if the transfer validator is not valid
85-
error InvalidTransferValidatorContract();
92+
error RoyaltyInvalidTransferValidatorContract();
93+
94+
/// @notice Revert with an error if the transfer validator is not valid
95+
error RoyaltyNotTransferValidator();
8696

8797
/*//////////////////////////////////////////////////////////////
8898
MODULE CONFIG
@@ -91,7 +101,7 @@ contract RoyaltyERC1155 is
91101
/// @notice Returns all implemented callback and module functions.
92102
function getModuleConfig() external pure virtual override returns (ModuleConfig memory config) {
93103
config.callbackFunctions = new CallbackFunction[](2);
94-
config.fallbackFunctions = new FallbackFunction[](8);
104+
config.fallbackFunctions = new FallbackFunction[](9);
95105

96106
config.callbackFunctions[0] = CallbackFunction(this.beforeTransferERC1155.selector);
97107
config.callbackFunctions[1] = CallbackFunction(this.beforeBatchTransferERC1155.selector);
@@ -105,11 +115,12 @@ contract RoyaltyERC1155 is
105115
FallbackFunction({selector: this.getTransferValidator.selector, permissionBits: 0});
106116
config.fallbackFunctions[4] =
107117
FallbackFunction({selector: this.getTransferValidationFunction.selector, permissionBits: 0});
108-
config.fallbackFunctions[5] =
109-
FallbackFunction({selector: this.setDefaultRoyaltyInfo.selector, permissionBits: Role._MANAGER_ROLE});
118+
config.fallbackFunctions[5] = FallbackFunction({selector: this.hasRole.selector, permissionBits: 0});
110119
config.fallbackFunctions[6] =
111-
FallbackFunction({selector: this.setRoyaltyInfoForToken.selector, permissionBits: Role._MANAGER_ROLE});
120+
FallbackFunction({selector: this.setDefaultRoyaltyInfo.selector, permissionBits: Role._MANAGER_ROLE});
112121
config.fallbackFunctions[7] =
122+
FallbackFunction({selector: this.setRoyaltyInfoForToken.selector, permissionBits: Role._MANAGER_ROLE});
123+
config.fallbackFunctions[8] =
113124
FallbackFunction({selector: this.setTransferValidator.selector, permissionBits: Role._MANAGER_ROLE});
114125

115126
config.requiredInterfaces = new bytes4[](1);
@@ -250,6 +261,16 @@ contract RoyaltyERC1155 is
250261
_setTransferValidator(validator);
251262
}
252263

264+
function hasRole(bytes32 role, address account) external view returns (bool) {
265+
if (msg.sender != _royaltyStorage().transferValidator) {
266+
revert RoyaltyNotTransferValidator();
267+
}
268+
if (role == DEFAULT_ACCESS_CONTROL_ADMIN_ROLE) {
269+
return OwnableRoles(address(this)).hasAllRoles(account, Role._MANAGER_ROLE);
270+
}
271+
return OwnableRoles(address(this)).hasAllRoles(account, uint256(role));
272+
}
273+
253274
/*//////////////////////////////////////////////////////////////
254275
INTERNAL FUNCTIONS
255276
//////////////////////////////////////////////////////////////*/
@@ -268,7 +289,7 @@ contract RoyaltyERC1155 is
268289
bool isValidTransferValidator = validator.code.length > 0;
269290

270291
if (validator != address(0) && !isValidTransferValidator) {
271-
revert InvalidTransferValidatorContract();
292+
revert RoyaltyInvalidTransferValidatorContract();
272293
}
273294

274295
emit TransferValidatorUpdated(address(getTransferValidator()), validator);

src/module/token/royalty/RoyaltyERC721.sol

+27-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
44
import {Module} from "../../../Module.sol";
55

66
import {Role} from "../../../Role.sol";
7+
import {OwnableRoles} from "@solady/auth/OwnableRoles.sol";
78

89
import {BeforeTransferCallbackERC721} from "../../../callback/BeforeTransferCallbackERC721.sol";
910
import {IInstallationCallback} from "../../../interface/IInstallationCallback.sol";
@@ -41,6 +42,12 @@ library RoyaltyStorage {
4142

4243
contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackERC721 {
4344

45+
/*//////////////////////////////////////////////////////////////
46+
CONSTANTS
47+
//////////////////////////////////////////////////////////////*/
48+
49+
bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;
50+
4451
/*//////////////////////////////////////////////////////////////
4552
STRUCTS
4653
//////////////////////////////////////////////////////////////*/
@@ -76,7 +83,10 @@ contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackE
7683
error RoyaltyExceedsMaxBps();
7784

7885
/// @notice Revert with an error if the transfer validator is not valid
79-
error InvalidTransferValidatorContract();
86+
error RoyaltyInvalidTransferValidatorContract();
87+
88+
/// @notice Revert with an error if the transfer validator is not valid
89+
error RoyaltyNotTransferValidator();
8090

8191
/*//////////////////////////////////////////////////////////////
8292
MODULE CONFIG
@@ -85,7 +95,7 @@ contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackE
8595
/// @notice Returns all implemented callback and module functions.
8696
function getModuleConfig() external pure virtual override returns (ModuleConfig memory config) {
8797
config.callbackFunctions = new CallbackFunction[](1);
88-
config.fallbackFunctions = new FallbackFunction[](8);
98+
config.fallbackFunctions = new FallbackFunction[](9);
8999

90100
config.callbackFunctions[0] = CallbackFunction(this.beforeTransferERC721.selector);
91101

@@ -98,11 +108,12 @@ contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackE
98108
FallbackFunction({selector: this.getTransferValidator.selector, permissionBits: 0});
99109
config.fallbackFunctions[4] =
100110
FallbackFunction({selector: this.getTransferValidationFunction.selector, permissionBits: 0});
101-
config.fallbackFunctions[5] =
102-
FallbackFunction({selector: this.setDefaultRoyaltyInfo.selector, permissionBits: Role._MANAGER_ROLE});
111+
config.fallbackFunctions[5] = FallbackFunction({selector: this.hasRole.selector, permissionBits: 0});
103112
config.fallbackFunctions[6] =
104-
FallbackFunction({selector: this.setRoyaltyInfoForToken.selector, permissionBits: Role._MANAGER_ROLE});
113+
FallbackFunction({selector: this.setDefaultRoyaltyInfo.selector, permissionBits: Role._MANAGER_ROLE});
105114
config.fallbackFunctions[7] =
115+
FallbackFunction({selector: this.setRoyaltyInfoForToken.selector, permissionBits: Role._MANAGER_ROLE});
116+
config.fallbackFunctions[8] =
106117
FallbackFunction({selector: this.setTransferValidator.selector, permissionBits: Role._MANAGER_ROLE});
107118

108119
config.requiredInterfaces = new bytes4[](1);
@@ -228,6 +239,16 @@ contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackE
228239
_setTransferValidator(validator);
229240
}
230241

242+
function hasRole(bytes32 role, address account) external view returns (bool) {
243+
if (msg.sender != _royaltyStorage().transferValidator) {
244+
revert RoyaltyNotTransferValidator();
245+
}
246+
if (role == DEFAULT_ACCESS_CONTROL_ADMIN_ROLE) {
247+
return OwnableRoles(address(this)).hasAllRoles(account, Role._MANAGER_ROLE);
248+
}
249+
return OwnableRoles(address(this)).hasAllRoles(account, uint256(role));
250+
}
251+
231252
/*//////////////////////////////////////////////////////////////
232253
INTERNAL FUNCTIONS
233254
//////////////////////////////////////////////////////////////*/
@@ -246,7 +267,7 @@ contract RoyaltyERC721 is Module, IInstallationCallback, BeforeTransferCallbackE
246267
bool isValidTransferValidator = validator.code.length > 0;
247268

248269
if (validator != address(0) && !isValidTransferValidator) {
249-
revert InvalidTransferValidatorContract();
270+
revert RoyaltyInvalidTransferValidatorContract();
250271
}
251272

252273
emit TransferValidatorUpdated(address(getTransferValidator()), validator);

test/module/royalty/RoyaltyERC1155.t.sol

+84-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,31 @@ contract TransferToken {
4141

4242
}
4343

44+
struct CollectionSecurityPolicyV3 {
45+
bool disableAuthorizationMode;
46+
bool authorizersCannotSetWildcardOperators;
47+
uint8 transferSecurityLevel;
48+
uint120 listId;
49+
bool enableAccountFreezingMode;
50+
uint16 tokenType;
51+
}
52+
53+
interface CreatorTokenTransferValidator is ITransferValidator {
54+
55+
function setTransferSecurityLevelOfCollection(
56+
address collection,
57+
uint8 transferSecurityLevel,
58+
bool isTransferRestricted,
59+
bool isTransferWithRestrictedRecipient,
60+
bool isTransferWithRestrictedToken
61+
) external;
62+
function getCollectionSecurityPolicy(address collection)
63+
external
64+
view
65+
returns (CollectionSecurityPolicyV3 memory);
66+
67+
}
68+
4469
contract RoyaltyERC1155Test is Test {
4570

4671
ERC1155Core public core;
@@ -49,7 +74,8 @@ contract RoyaltyERC1155Test is Test {
4974

5075
MintableERC1155 public mintableModuleImplementation;
5176
TransferToken public transferTokenContract;
52-
ITransferValidator public mockTransferValidator;
77+
CreatorTokenTransferValidator public mockTransferValidator;
78+
uint8 TRANSFER_SECURITY_LEVEL_SEVEN = 7;
5379

5480
uint256 ownerPrivateKey = 1;
5581
address public owner;
@@ -133,7 +159,7 @@ contract RoyaltyERC1155Test is Test {
133159
core.grantRoles(owner, Role._MINTER_ROLE);
134160

135161
// set up transfer validator
136-
mockTransferValidator = ITransferValidator(0x721C0078c2328597Ca70F5451ffF5A7B38D4E947);
162+
mockTransferValidator = CreatorTokenTransferValidator(0x721C0078c2328597Ca70F5451ffF5A7B38D4E947);
137163
vm.etch(address(mockTransferValidator), TRANSFER_VALIDATOR_DEPLOYED_BYTECODE);
138164
}
139165

@@ -247,7 +273,7 @@ contract RoyaltyERC1155Test is Test {
247273
function test_revert_setTransferValidator_invalidContract() public {
248274
// attempt to set the transfer validator to an invalid contract
249275
vm.prank(owner);
250-
vm.expectRevert(RoyaltyERC1155.InvalidTransferValidatorContract.selector);
276+
vm.expectRevert(RoyaltyERC1155.RoyaltyInvalidTransferValidatorContract.selector);
251277
RoyaltyERC1155(address(core)).setTransferValidator(address(11_111));
252278
}
253279

@@ -323,6 +349,61 @@ contract RoyaltyERC1155Test is Test {
323349
assertEq(0, core.balanceOf(permissionedActor, 1));
324350
}
325351

352+
/*///////////////////////////////////////////////////////////////
353+
Unit tests: `setTransferPolicy`
354+
//////////////////////////////////////////////////////////////*/
355+
356+
function test_setTransferSecurityLevel() public {
357+
if (evmVersionHash != keccak256(abi.encode('evm_version = "cancun"'))) {
358+
//skip test if evm version is not cancun
359+
return;
360+
}
361+
362+
// set transfer validator
363+
vm.prank(owner);
364+
RoyaltyERC1155(address(core)).setTransferValidator(address(mockTransferValidator));
365+
366+
vm.prank(owner);
367+
core.grantRoles(permissionedActor, Role._MANAGER_ROLE);
368+
369+
vm.prank(permissionedActor);
370+
mockTransferValidator.setTransferSecurityLevelOfCollection(
371+
address(core), TRANSFER_SECURITY_LEVEL_SEVEN, true, false, false
372+
);
373+
374+
assertEq(
375+
mockTransferValidator.getCollectionSecurityPolicy(address(core)).transferSecurityLevel,
376+
TRANSFER_SECURITY_LEVEL_SEVEN
377+
);
378+
}
379+
380+
function test_revert_setTransferSecurityLevel() public {
381+
if (evmVersionHash != keccak256(abi.encode('evm_version = "cancun"'))) {
382+
//skip test if evm version is not cancun
383+
return;
384+
}
385+
vm.prank(owner);
386+
core.grantRoles(permissionedActor, Role._MANAGER_ROLE);
387+
388+
// revert due to msg.sender not being the transfer validator
389+
vm.expectRevert();
390+
vm.prank(permissionedActor);
391+
mockTransferValidator.setTransferSecurityLevelOfCollection(
392+
address(core), TRANSFER_SECURITY_LEVEL_SEVEN, true, false, false
393+
);
394+
395+
// set transfer validator
396+
vm.prank(owner);
397+
RoyaltyERC1155(address(core)).setTransferValidator(address(mockTransferValidator));
398+
399+
// revert due to incorrect permissions
400+
vm.prank(unpermissionedActor);
401+
vm.expectRevert();
402+
mockTransferValidator.setTransferSecurityLevelOfCollection(
403+
address(core), TRANSFER_SECURITY_LEVEL_SEVEN, true, false, false
404+
);
405+
}
406+
326407
/*///////////////////////////////////////////////////////////////
327408
UTILITY FUNCTIONS
328409
//////////////////////////////////////////////////////////////*/

0 commit comments

Comments
 (0)