@@ -16,49 +16,77 @@ import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
1616*/
1717
1818abstract contract ImmutableERC721RoyaltyEnforced is
19- ERC721 , AccessControlEnumerable
19+ ERC721 ,
20+ AccessControlEnumerable
2021{
2122 /// ===== Errors =====
2223
2324 /// @dev Error thrown when calling address is not Allowlisted
2425 error CallerNotInAllowlist (address caller );
2526
27+ /// @dev Error thrown when 'from' address is not Allowlisted
28+ error TransferFromNotInAllowlist (address from );
29+
30+ /// @dev Error thrown when 'to' address is not Allowlisted
31+ error TransferToNotInAllowlist (address to );
32+
2633 /// @dev Error thrown when approve target is not Allowlisted
2734 error ApproveTargetNotInAllowlist (address target );
2835
36+ /// @dev Error thrown when approve target is not Allowlisted
37+ error ApproverNotInAllowlist (address approver );
38+
2939 /// ===== Events =====
3040
3141 /// @dev Emitted whenever the transfer Allowlist registry is updated
32- event RoyaltytAllowlistRegistryUpdated (address oldRegistry , address newRegistry );
42+ event RoyaltytAllowlistRegistryUpdated (
43+ address oldRegistry ,
44+ address newRegistry
45+ );
3346
3447 /// ===== State Variables =====
35-
48+
3649 /// @dev Interface that implements the `IRoyaltyAllowlist` interface
3750 IRoyaltyAllowlist public royaltyAllowlist;
3851
3952 /// ===== External functions =====
4053
4154 /// @dev Returns the supported interfaces
42- function supportsInterface (bytes4 interfaceId )
55+ function supportsInterface (
56+ bytes4 interfaceId
57+ )
4358 public
4459 view
4560 virtual
46- override (ERC721 , AccessControlEnumerable)
61+ override (ERC721 , AccessControlEnumerable)
4762 returns (bool )
4863 {
4964 return super .supportsInterface (interfaceId);
5065 }
5166
5267 /// @dev Allows admin to set or update the royalty Allowlist registry
53- function setRoyaltyAllowlistRegistry (address _royaltyAllowlist ) public onlyRole (DEFAULT_ADMIN_ROLE) {
54- require (IERC165 (_royaltyAllowlist).supportsInterface (type (IRoyaltyAllowlist).interfaceId), "contract does not implement IRoyaltyAllowlist " );
55-
56- emit RoyaltytAllowlistRegistryUpdated (address (royaltyAllowlist), _royaltyAllowlist);
68+ function setRoyaltyAllowlistRegistry (
69+ address _royaltyAllowlist
70+ ) public onlyRole (DEFAULT_ADMIN_ROLE) {
71+ require (
72+ IERC165 (_royaltyAllowlist).supportsInterface (
73+ type (IRoyaltyAllowlist).interfaceId
74+ ),
75+ "contract does not implement IRoyaltyAllowlist "
76+ );
77+
78+ emit RoyaltytAllowlistRegistryUpdated (
79+ address (royaltyAllowlist),
80+ _royaltyAllowlist
81+ );
5782 royaltyAllowlist = IRoyaltyAllowlist (_royaltyAllowlist);
5883 }
5984
6085 /// @dev Override of setApprovalForAll from {ERC721}, with added Allowlist approval validation
61- function setApprovalForAll (address operator , bool approved ) public virtual override {
86+ function setApprovalForAll (
87+ address operator ,
88+ bool approved
89+ ) public virtual override {
6290 _validateApproval (operator);
6391 super .setApprovalForAll (operator, approved);
6492 }
@@ -72,41 +100,70 @@ abstract contract ImmutableERC721RoyaltyEnforced is
72100 /// @dev Internal function to validate whether approval targets are Allowlisted or EOA
73101 function _validateApproval (address targetApproval ) internal view {
74102 // Only check if the registry is set
75- if (address (royaltyAllowlist) != address (0 )) {
76- // Check for:
103+ if (address (royaltyAllowlist) != address (0 )) {
104+ // Check for:
105+ // 1. approver is an EOA. Contract constructor is handled as transfers 'from' are blocked
106+ // 2. approver is address or bytecode is allowlisted
107+ if (
108+ msg .sender .code.length != 0 &&
109+ ! royaltyAllowlist.isAllowlisted (msg .sender )
110+ ) {
111+ revert ApproverNotInAllowlist (msg .sender );
112+ }
113+
114+ // Check for:
77115 // 1. approval target is an EOA
78116 // 2. approval target address is Allowlisted or target address bytecode is Allowlisted
79- if (targetApproval.code.length == 0 || royaltyAllowlist.isAllowlisted (targetApproval)){
80- return ;
117+ if (
118+ targetApproval.code.length != 0 &&
119+ ! royaltyAllowlist.isAllowlisted (targetApproval)
120+ ) {
121+ revert ApproveTargetNotInAllowlist (targetApproval);
81122 }
82- revert ApproveTargetNotInAllowlist (targetApproval);
83123 }
84124 }
85125
86126 /// ===== Internal functions =====
87127
88128 /// @dev Override of internal transfer from {ERC721} function to include validation
89- function _transfer (
129+ function _transfer (
90130 address from ,
91131 address to ,
92132 uint256 tokenId
93133 ) internal virtual override (ERC721 ) {
94- _validateTransfer ();
134+ _validateTransfer (from, to );
95135 super ._transfer (from, to, tokenId);
96136 }
97137
98138 /// @dev Internal function to validate whether the calling address is an EOA or Allowlisted
99- function _validateTransfer () internal view {
139+ function _validateTransfer (address from , address to ) internal view {
100140 // Only check if the registry is set
101141 if (address (royaltyAllowlist) != address (0 )) {
102142 // Check for:
103143 // 1. caller is an EOA
104144 // 2. caller is Allowlisted or is the calling address bytecode is Allowlisted
105- if (msg .sender == tx .origin || royaltyAllowlist.isAllowlisted (msg .sender ))
106- {
107- return ;
145+ if (
146+ msg .sender != tx .origin &&
147+ ! royaltyAllowlist.isAllowlisted (msg .sender )
148+ ) {
149+ revert CallerNotInAllowlist (msg .sender );
150+ }
151+
152+ // Check for:
153+ // 1. from is an EOA
154+ // 2. from is Allowlisted or from address bytecode is Allowlisted
155+ if (
156+ from.code.length != 0 && ! royaltyAllowlist.isAllowlisted (from)
157+ ) {
158+ revert TransferFromNotInAllowlist (from);
159+ }
160+
161+ // Check for:
162+ // 1. to is an EOA
163+ // 2. to is Allowlisted or to address bytecode is Allowlisted
164+ if (to.code.length != 0 && ! royaltyAllowlist.isAllowlisted (to)) {
165+ revert TransferToNotInAllowlist (to);
108166 }
109- revert CallerNotInAllowlist (msg .sender );
110167 }
111168 }
112169}
0 commit comments