Skip to content

Commit 13c110d

Browse files
committed
imported over test OperatorAllowlist
1 parent f7104e6 commit 13c110d

2 files changed

Lines changed: 183 additions & 0 deletions

File tree

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright Immutable Pty Ltd 2018 - 2023
2+
// SPDX-License-Identifier: Apache 2.0
3+
pragma solidity 0.8.19;
4+
5+
// Access Control
6+
7+
import {Role} from "../../../Role.sol";
8+
import {OwnableRoles} from "@solady/auth/OwnableRoles.sol";
9+
10+
// Interfaces
11+
import {IOperatorAllowlist} from "../../allowlist/IOperatorAllowlist.sol";
12+
13+
// Interface to retrieve the implemention stored inside the Proxy contract
14+
interface IProxy {
15+
16+
// Returns the current implementation address used by the proxy contract
17+
// solhint-disable-next-line func-name-mixedcase
18+
function PROXY_getImplementation() external view returns (address);
19+
20+
}
21+
22+
interface IERC165 {
23+
24+
function supportsInterface(bytes4 interfaceId) external view returns (bool);
25+
26+
}
27+
28+
/*
29+
OperatorAllowlist is an implementation of a Allowlist registry, storing addresses and bytecode
30+
which are allowed to be approved operators and execute transfers of interfacing token contracts (admin, ).
31+
The registry will be a deployed contract that tokens may interface with and point to.
32+
OperatorAllowlist is not designed to be upgradeable or extended.
33+
*/
34+
35+
contract OperatorAllowlist is ERC165, AccessControl, IOperatorAllowlist {
36+
37+
/// @notice Mapping of Allowlisted addresses
38+
mapping(address aContract => bool allowed) private addressAllowlist;
39+
40+
/// @notice Mapping of Allowlisted implementation addresses
41+
mapping(address impl => bool allowed) private addressImplementationAllowlist;
42+
43+
/// @notice Mapping of Allowlisted bytecodes
44+
mapping(bytes32 bytecodeHash => bool allowed) private bytecodeAllowlist;
45+
46+
/// ===== Events =====
47+
48+
/// @notice Emitted when a target address is added or removed from the Allowlist
49+
event AddressAllowlistChanged(address indexed target, bool added);
50+
51+
/// @notice Emitted when a target smart contract wallet is added or removed from the Allowlist
52+
event WalletAllowlistChanged(bytes32 indexed targetBytes, address indexed targetAddress, bool added);
53+
54+
/// ===== Constructor =====
55+
56+
/**
57+
* @notice Grants `_MANAGER_ROLE` to the supplied `admin` address
58+
* @param admin the address to grant `_MANAGER_ROLE` to
59+
*/
60+
constructor(address admin) {
61+
_grantRoles(admin, _MANAGER_ROLE);
62+
}
63+
64+
/// ===== External functions =====
65+
66+
/**
67+
* @notice Add a target address to Allowlist
68+
* @param addressTargets the addresses to be added to the allowlist
69+
*/
70+
function addAddressToAllowlist(address[] calldata addressTargets) external onlyRoles(_REGISTRAR_ROLE) {
71+
for (uint256 i; i < addressTargets.length; i++) {
72+
addressAllowlist[addressTargets[i]] = true;
73+
emit AddressAllowlistChanged(addressTargets[i], true);
74+
}
75+
}
76+
77+
/**
78+
* @notice Remove a target address from Allowlist
79+
* @param addressTargets the addresses to be removed from the allowlist
80+
*/
81+
function removeAddressFromAllowlist(address[] calldata addressTargets) external onlyRoles(_REGISTRAR_ROLE) {
82+
for (uint256 i; i < addressTargets.length; i++) {
83+
delete addressAllowlist[addressTargets[i]];
84+
emit AddressAllowlistChanged(addressTargets[i], false);
85+
}
86+
}
87+
88+
/**
89+
* @notice Add a smart contract wallet to the Allowlist.
90+
* This will allowlist the proxy and implementation contract pair.
91+
* First, the bytecode of the proxy is added to the bytecode allowlist.
92+
* Second, the implementation address stored in the proxy is stored in the
93+
* implementation address allowlist.
94+
* @param walletAddr the wallet address to be added to the allowlist
95+
*/
96+
function addWalletToAllowlist(address walletAddr) external onlyRoles(_REGISTRAR_ROLE) {
97+
// get bytecode of wallet
98+
bytes32 codeHash;
99+
// solhint-disable-next-line no-inline-assembly
100+
assembly {
101+
codeHash := extcodehash(walletAddr)
102+
}
103+
bytecodeAllowlist[codeHash] = true;
104+
// get address of wallet module
105+
address impl = IProxy(walletAddr).PROXY_getImplementation();
106+
addressImplementationAllowlist[impl] = true;
107+
108+
emit WalletAllowlistChanged(codeHash, walletAddr, true);
109+
}
110+
111+
/**
112+
* @notice Remove a smart contract wallet from the Allowlist
113+
* This will remove the proxy bytecode hash and implementation contract address pair from the allowlist
114+
* @param walletAddr the wallet address to be removed from the allowlist
115+
*/
116+
function removeWalletFromAllowlist(address walletAddr) external onlyRoles(_REGISTRAR_ROLE) {
117+
// get bytecode of wallet
118+
bytes32 codeHash;
119+
// solhint-disable-next-line no-inline-assembly
120+
assembly {
121+
codeHash := extcodehash(walletAddr)
122+
}
123+
delete bytecodeAllowlist[codeHash];
124+
// get address of wallet module
125+
address impl = IProxy(walletAddr).PROXY_getImplementation();
126+
delete addressImplementationAllowlist[impl];
127+
128+
emit WalletAllowlistChanged(codeHash, walletAddr, false);
129+
}
130+
131+
/**
132+
* @notice Allows admin to grant `user` `_REGISTRAR_ROLE` role
133+
* @param user the address that `_REGISTRAR_ROLE` will be granted to
134+
*/
135+
function grantRegistrarRole(address user) external onlyRoles(_MANAGER_ROLE) {
136+
grantRoles(user, _REGISTRAR_ROLE);
137+
}
138+
139+
/**
140+
* @notice Allows admin to revoke `_REGISTRAR_ROLE` role from `user`
141+
* @param user the address that `_REGISTRAR_ROLE` will be revoked from
142+
*/
143+
function revokeRegistrarRole(address user) external onlyRoles(_MANAGER_ROLE) {
144+
revokeRole(user, _REGISTRAR_ROLE);
145+
}
146+
147+
/// ===== View functions =====
148+
149+
/**
150+
* @notice Returns true if an address is Allowlisted, false otherwise
151+
* @param target the address that will be checked for presence in the allowlist
152+
*/
153+
function isAllowlisted(address target) external view override returns (bool) {
154+
if (addressAllowlist[target]) {
155+
return true;
156+
}
157+
158+
// Check if caller is a Allowlisted smart contract wallet
159+
bytes32 codeHash;
160+
// solhint-disable-next-line no-inline-assembly
161+
assembly {
162+
codeHash := extcodehash(target)
163+
}
164+
if (bytecodeAllowlist[codeHash]) {
165+
// If wallet proxy bytecode is approved, check addr of implementation contract
166+
address impl = IProxy(target).PROXY_getImplementation();
167+
168+
return addressImplementationAllowlist[impl];
169+
}
170+
171+
return false;
172+
}
173+
174+
/**
175+
* @notice ERC-165 interface support
176+
* @param interfaceId The interface identifier, which is a 4-byte selector.
177+
*/
178+
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, AccessControl) returns (bool) {
179+
return interfaceId == type(IOperatorAllowlist).interfaceId || super.supportsInterface(interfaceId);
180+
}
181+
182+
}

src/Role.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ library Role {
99

1010
uint256 internal constant _MINTER_ROLE = 1 << 0;
1111
uint256 internal constant _MANAGER_ROLE = 1 << 1;
12+
uint256 internal constant _REGISTRAR_ROLE = 1 << 2;
1213

1314
uint256 internal constant _INSTALLER_ROLE = 1 << 255;
1415

0 commit comments

Comments
 (0)