@layerzerolabs/utils-upgradeable-evm-contracts 0.2.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-lint.log +491 -0
- package/.turbo/turbo-test.log +1356 -0
- package/LICENSE +23 -0
- package/contracts/access/AccessControl2StepUpgradeable.sol +144 -0
- package/contracts/allowlist/AllowlistBaseUpgradeable.sol +184 -0
- package/contracts/allowlist/AllowlistRBACUpgradeable.sol +55 -0
- package/contracts/fee-accounting/FeeHandlerBaseUpgradeable.sol +69 -0
- package/contracts/fee-accounting/FeeHandlerRBACUpgradeable.sol +34 -0
- package/contracts/fee-config/FeeConfigBaseUpgradeable.sol +128 -0
- package/contracts/fee-config/FeeConfigRBACUpgradeable.sol +44 -0
- package/contracts/libs/EnumerableSetPagination.sol +77 -0
- package/contracts/pause/PauseBaseUpgradeable.sol +107 -0
- package/contracts/pause/PauseRBACUpgradeable.sol +47 -0
- package/contracts/pause-by-id/PauseByIDBaseUpgradeable.sol +127 -0
- package/contracts/pause-by-id/PauseByIDRBACUpgradeable.sol +74 -0
- package/contracts/rate-limiter/RateLimiterBaseUpgradeable.sol +636 -0
- package/contracts/rate-limiter/RateLimiterRBACUpgradeable.sol +89 -0
- package/contracts/rate-limiter/libs/RateLimiterUtils.sol +82 -0
- package/foundry.toml +27 -0
- package/package.json +34 -0
- package/solhint.config.js +3 -0
- package/test/AccessControl2StepUpgradeable.t.sol +374 -0
- package/test/AllowlistBaseUpgradeable.t.sol +380 -0
- package/test/AllowlistRBACUpgradeable.t.sol +84 -0
- package/test/EnumerableSetPagination.t.sol +445 -0
- package/test/FeeConfigBaseUpgradeable.t.sol +232 -0
- package/test/FeeConfigRBACUpgradeable.t.sol +59 -0
- package/test/FeeHandlerBaseUpgradeable.t.sol +78 -0
- package/test/FeeHandlerRBACUpgradeable.t.sol +45 -0
- package/test/PauseBaseUpgradeable.t.sol +244 -0
- package/test/PauseByIDBaseUpgradeable.t.sol +337 -0
- package/test/PauseByIDRBACUpgradeable.t.sol +414 -0
- package/test/PauseRBACUpgradeable.t.sol +258 -0
- package/test/RateLimiterBaseUpgradeable.t.sol +826 -0
- package/test/RateLimiterRBACUpgradeable.t.sol +128 -0
- package/test/RateLimiterRBACUpgradeableInvariant.t.sol +444 -0
- package/test/RateLimiterUtils.t.sol +137 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2026 - LayerZero Labs Ltd.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any
|
|
4
|
+
person obtaining a copy of this software and associated
|
|
5
|
+
documentation files (the "Software"), to deal in the
|
|
6
|
+
Software without restriction, including without
|
|
7
|
+
limitation the rights to use, copy, modify, merge,
|
|
8
|
+
publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software
|
|
10
|
+
is furnished to do so, subject to the following
|
|
11
|
+
conditions:
|
|
12
|
+
The above copyright notice and this permission notice
|
|
13
|
+
shall be included in all copies or substantial portions
|
|
14
|
+
of the Software.
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
16
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
17
|
+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
18
|
+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
19
|
+
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
22
|
+
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
23
|
+
DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IAccessControl2Step } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IAccessControl2Step.sol";
|
|
5
|
+
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
6
|
+
import { AccessControlEnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title AccessControl2StepUpgradeable
|
|
10
|
+
* @author LayerZero Labs (tinom.eth)
|
|
11
|
+
* @custom:version 1.0.0
|
|
12
|
+
* @notice Abstract upgradeable contract that extends `AccessControlEnumerable` with a two-step transfer mechanism for
|
|
13
|
+
* the `DEFAULT_ADMIN_ROLE`, similar to `AccessControlDefaultAdminRules`. It does not enforce delayed transfers.
|
|
14
|
+
* @dev The `DEFAULT_ADMIN_ROLE` cannot be granted or revoked through the standard `grantRole` and `revokeRole`
|
|
15
|
+
* functions. Instead, a two-step process is enforced:
|
|
16
|
+
* 1. The current admin calls `beginDefaultAdminTransfer(newAdmin)`.
|
|
17
|
+
* 2. The pending admin calls `acceptDefaultAdminTransfer()`.
|
|
18
|
+
* The current default admin can cancel a pending transfer via `beginDefaultAdminTransfer(address(0))`.
|
|
19
|
+
* Renouncing the `DEFAULT_ADMIN_ROLE` is not permitted.
|
|
20
|
+
*/
|
|
21
|
+
abstract contract AccessControl2StepUpgradeable is IAccessControl2Step, AccessControlEnumerableUpgradeable {
|
|
22
|
+
/// @custom:storage-location erc7201:layerzerov2.storage.accesscontrol2step
|
|
23
|
+
struct AccessControl2StepStorage {
|
|
24
|
+
address _pendingDefaultAdmin;
|
|
25
|
+
address _currentDefaultAdmin;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.accesscontrol2step")) - 1)) & ~bytes32(uint256(0xff))
|
|
29
|
+
bytes32 private constant ACCESS_CONTROL_2_STEP_STORAGE_LOCATION =
|
|
30
|
+
0x9ab055b8fb8e38b861ceee93a65f20f7a2382a86570a6abe934fe7edfac60400;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @notice Internal function to get the contract storage.
|
|
34
|
+
* @return $ Storage pointer
|
|
35
|
+
*/
|
|
36
|
+
function _getAccessControl2StepStorage() internal pure returns (AccessControl2StepStorage storage $) {
|
|
37
|
+
assembly {
|
|
38
|
+
$.slot := ACCESS_CONTROL_2_STEP_STORAGE_LOCATION
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @notice Initializes the contract.
|
|
44
|
+
* @param _initialDefaultAdmin Default admin address
|
|
45
|
+
*/
|
|
46
|
+
function __AccessControl2Step_init(address _initialDefaultAdmin) internal onlyInitializing {
|
|
47
|
+
__AccessControl2Step_init_unchained(_initialDefaultAdmin);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @notice Unchained initialization function for the contract.
|
|
52
|
+
* @param _initialDefaultAdmin Default admin address
|
|
53
|
+
*/
|
|
54
|
+
function __AccessControl2Step_init_unchained(address _initialDefaultAdmin) internal onlyInitializing {
|
|
55
|
+
if (_initialDefaultAdmin == address(0)) {
|
|
56
|
+
revert InvalidDefaultAdmin(address(0));
|
|
57
|
+
}
|
|
58
|
+
AccessControl2StepStorage storage $ = _getAccessControl2StepStorage();
|
|
59
|
+
$._currentDefaultAdmin = _initialDefaultAdmin;
|
|
60
|
+
/// @dev Bypass `DEFAULT_ADMIN_ROLE` check.
|
|
61
|
+
super._grantRole(DEFAULT_ADMIN_ROLE, _initialDefaultAdmin);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============ Getters ============
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @inheritdoc IAccessControl2Step
|
|
68
|
+
*/
|
|
69
|
+
function defaultAdmin() public view virtual returns (address defaultAdminAddress) {
|
|
70
|
+
return _getAccessControl2StepStorage()._currentDefaultAdmin;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @inheritdoc IAccessControl2Step
|
|
75
|
+
*/
|
|
76
|
+
function pendingDefaultAdmin() public view virtual returns (address pendingDefaultAdminAddress) {
|
|
77
|
+
return _getAccessControl2StepStorage()._pendingDefaultAdmin;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============ Setters ============
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @inheritdoc IAccessControl2Step
|
|
84
|
+
*/
|
|
85
|
+
function beginDefaultAdminTransfer(address _newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
86
|
+
AccessControl2StepStorage storage $ = _getAccessControl2StepStorage();
|
|
87
|
+
$._pendingDefaultAdmin = _newAdmin;
|
|
88
|
+
emit DefaultAdminTransferStarted(_newAdmin);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @inheritdoc IAccessControl2Step
|
|
93
|
+
*/
|
|
94
|
+
function acceptDefaultAdminTransfer() public virtual {
|
|
95
|
+
AccessControl2StepStorage storage $ = _getAccessControl2StepStorage();
|
|
96
|
+
|
|
97
|
+
address pendingAdmin = $._pendingDefaultAdmin;
|
|
98
|
+
if (pendingAdmin != _msgSender()) {
|
|
99
|
+
revert CallerNotPendingAdmin(pendingAdmin);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// @dev Bypass `DEFAULT_ADMIN_ROLE` check.
|
|
103
|
+
super._revokeRole(DEFAULT_ADMIN_ROLE, $._currentDefaultAdmin);
|
|
104
|
+
super._grantRole(DEFAULT_ADMIN_ROLE, pendingAdmin);
|
|
105
|
+
|
|
106
|
+
$._currentDefaultAdmin = pendingAdmin;
|
|
107
|
+
delete $._pendingDefaultAdmin;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============ Overrides ============
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @dev Override to prevent granting `DEFAULT_ADMIN_ROLE`.
|
|
114
|
+
* @inheritdoc AccessControlEnumerableUpgradeable
|
|
115
|
+
*/
|
|
116
|
+
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
|
|
117
|
+
if (role == DEFAULT_ADMIN_ROLE) {
|
|
118
|
+
revert AccessControlEnforcedDefaultAdminRules();
|
|
119
|
+
}
|
|
120
|
+
return super._grantRole(role, account);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @dev Override to prevent revoking `DEFAULT_ADMIN_ROLE`.
|
|
125
|
+
* @inheritdoc AccessControlEnumerableUpgradeable
|
|
126
|
+
*/
|
|
127
|
+
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
|
|
128
|
+
if (role == DEFAULT_ADMIN_ROLE) {
|
|
129
|
+
revert AccessControlEnforcedDefaultAdminRules();
|
|
130
|
+
}
|
|
131
|
+
return super._revokeRole(role, account);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @dev Override to prevent updating the admin of the `DEFAULT_ADMIN_ROLE`.
|
|
136
|
+
* @inheritdoc AccessControlUpgradeable
|
|
137
|
+
*/
|
|
138
|
+
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
|
|
139
|
+
if (role == DEFAULT_ADMIN_ROLE) {
|
|
140
|
+
revert AccessControlEnforcedDefaultAdminRules();
|
|
141
|
+
}
|
|
142
|
+
super._setRoleAdmin(role, adminRole);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IAllowlist } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IAllowlist.sol";
|
|
5
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
7
|
+
import { EnumerableSetPagination } from "./../libs/EnumerableSetPagination.sol";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @title AllowlistBaseUpgradeable
|
|
11
|
+
* @author LayerZero Labs (tinom.eth)
|
|
12
|
+
* @custom:version 1.0.0
|
|
13
|
+
* @notice Abstract upgradeable contract that provides toggleable allowlist functionality between open, blacklist, and
|
|
14
|
+
* whitelist modes.
|
|
15
|
+
* @dev No public management functions are exposed by this contract, wrappers should be used with access control.
|
|
16
|
+
* Alternatively, refer to `AllowlistRBACUpgradeable` for a permissioned implementation.
|
|
17
|
+
*/
|
|
18
|
+
abstract contract AllowlistBaseUpgradeable is IAllowlist, Initializable {
|
|
19
|
+
using EnumerableSet for EnumerableSet.AddressSet;
|
|
20
|
+
using EnumerableSetPagination for EnumerableSet.AddressSet;
|
|
21
|
+
|
|
22
|
+
/// @custom:storage-location erc7201:layerzerov2.storage.allowlist
|
|
23
|
+
struct AllowlistStorage {
|
|
24
|
+
AllowlistMode mode;
|
|
25
|
+
EnumerableSet.AddressSet blacklistedSet;
|
|
26
|
+
EnumerableSet.AddressSet whitelistedSet;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.allowlist")) - 1)) & ~bytes32(uint256(0xff))
|
|
30
|
+
bytes32 private constant ALLOWLIST_STORAGE_LOCATION =
|
|
31
|
+
0xa9f917c522fb3fd8673bbc655e92a5c1f1ee3df7bf7ad06a1821b937d0205e00;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @notice Internal function to get the allowlist storage.
|
|
35
|
+
* @return $ Storage pointer
|
|
36
|
+
*/
|
|
37
|
+
function _getAllowlistStorage() internal pure returns (AllowlistStorage storage $) {
|
|
38
|
+
assembly {
|
|
39
|
+
$.slot := ALLOWLIST_STORAGE_LOCATION
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @notice Initializes the contract.
|
|
45
|
+
* @param _mode Initial mode
|
|
46
|
+
*/
|
|
47
|
+
function __AllowlistBase_init(AllowlistMode _mode) internal onlyInitializing {
|
|
48
|
+
__AllowlistBase_init_unchained(_mode);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @notice Unchained initialization function for the contract.
|
|
53
|
+
* @param _mode Initial mode
|
|
54
|
+
*/
|
|
55
|
+
function __AllowlistBase_init_unchained(AllowlistMode _mode) internal onlyInitializing {
|
|
56
|
+
/// @dev Not using `_setAllowlistMode` to avoid reverting if the mode is open.
|
|
57
|
+
AllowlistStorage storage $ = _getAllowlistStorage();
|
|
58
|
+
$.mode = _mode;
|
|
59
|
+
emit AllowlistModeUpdated(_mode);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @notice Modifier that reverts if the user is not allowlisted.
|
|
64
|
+
* @param _user User address
|
|
65
|
+
*/
|
|
66
|
+
modifier onlyAllowlisted(address _user) {
|
|
67
|
+
if (!isAllowlisted(_user)) revert NotAllowlisted(_user, allowlistMode());
|
|
68
|
+
_;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @inheritdoc IAllowlist
|
|
73
|
+
*/
|
|
74
|
+
function allowlistMode() public view virtual returns (AllowlistMode mode) {
|
|
75
|
+
return _getAllowlistStorage().mode;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @inheritdoc IAllowlist
|
|
80
|
+
*/
|
|
81
|
+
function isBlacklisted(address _user) public view virtual returns (bool isUserBlacklisted) {
|
|
82
|
+
return _getAllowlistStorage().blacklistedSet.contains(_user);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @inheritdoc IAllowlist
|
|
87
|
+
*/
|
|
88
|
+
function isWhitelisted(address _user) public view virtual returns (bool isUserWhitelisted) {
|
|
89
|
+
return _getAllowlistStorage().whitelistedSet.contains(_user);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @inheritdoc IAllowlist
|
|
94
|
+
*/
|
|
95
|
+
function isAllowlisted(address _user) public view virtual returns (bool isUserAllowlisted) {
|
|
96
|
+
AllowlistMode currentMode = allowlistMode();
|
|
97
|
+
if (currentMode == AllowlistMode.Open) return true;
|
|
98
|
+
if (currentMode == AllowlistMode.Blacklist) return !isBlacklisted(_user);
|
|
99
|
+
/// @dev `currentMode == AllowlistMode.Whitelist`.
|
|
100
|
+
return isWhitelisted(_user);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @inheritdoc IAllowlist
|
|
105
|
+
*/
|
|
106
|
+
function blacklistedCount() public view virtual returns (uint256 count) {
|
|
107
|
+
return _getAllowlistStorage().blacklistedSet.length();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @inheritdoc IAllowlist
|
|
112
|
+
*/
|
|
113
|
+
function whitelistedCount() public view virtual returns (uint256 count) {
|
|
114
|
+
return _getAllowlistStorage().whitelistedSet.length();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @inheritdoc IAllowlist
|
|
119
|
+
*/
|
|
120
|
+
function getBlacklist(uint256 _offset, uint256 _limit) public view virtual returns (address[] memory addresses) {
|
|
121
|
+
return _getAllowlistStorage().blacklistedSet.paginate(_offset, _limit);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @inheritdoc IAllowlist
|
|
126
|
+
*/
|
|
127
|
+
function getWhitelist(uint256 _offset, uint256 _limit) public view virtual returns (address[] memory addresses) {
|
|
128
|
+
return _getAllowlistStorage().whitelistedSet.paginate(_offset, _limit);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============ Internal Functions to Wrap with Access Control ============
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @notice Internal function to set the allowlist mode.
|
|
135
|
+
* @dev To be wrapped with access control.
|
|
136
|
+
* @param _mode New mode
|
|
137
|
+
*/
|
|
138
|
+
function _setAllowlistMode(AllowlistMode _mode) internal virtual {
|
|
139
|
+
AllowlistStorage storage $ = _getAllowlistStorage();
|
|
140
|
+
if ($.mode == _mode) revert ModeAlreadySet(_mode);
|
|
141
|
+
$.mode = _mode;
|
|
142
|
+
emit AllowlistModeUpdated(_mode);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @notice Internal function to set the whitelist state for an array of users.
|
|
147
|
+
* @dev To be wrapped with access control.
|
|
148
|
+
* @param _params Array of users and whitelist states
|
|
149
|
+
*/
|
|
150
|
+
function _setWhitelisted(SetAllowlistParam[] calldata _params) internal virtual {
|
|
151
|
+
AllowlistStorage storage $ = _getAllowlistStorage();
|
|
152
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
153
|
+
SetAllowlistParam calldata param = _params[i];
|
|
154
|
+
bool addedOrRemoved;
|
|
155
|
+
if (param.isEnabled) {
|
|
156
|
+
addedOrRemoved = $.whitelistedSet.add(param.user);
|
|
157
|
+
} else {
|
|
158
|
+
addedOrRemoved = $.whitelistedSet.remove(param.user);
|
|
159
|
+
}
|
|
160
|
+
if (!addedOrRemoved) revert AllowlistStateIdempotent(param.user, param.isEnabled);
|
|
161
|
+
emit WhitelistUpdated(param.user, param.isEnabled);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @notice Internal function to set the blacklist state for an array of users.
|
|
167
|
+
* @dev To be wrapped with access control.
|
|
168
|
+
* @param _params Array of users and blacklist states
|
|
169
|
+
*/
|
|
170
|
+
function _setBlacklisted(SetAllowlistParam[] calldata _params) internal virtual {
|
|
171
|
+
AllowlistStorage storage $ = _getAllowlistStorage();
|
|
172
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
173
|
+
SetAllowlistParam calldata param = _params[i];
|
|
174
|
+
bool addedOrRemoved;
|
|
175
|
+
if (param.isEnabled) {
|
|
176
|
+
addedOrRemoved = $.blacklistedSet.add(param.user);
|
|
177
|
+
} else {
|
|
178
|
+
addedOrRemoved = $.blacklistedSet.remove(param.user);
|
|
179
|
+
}
|
|
180
|
+
if (!addedOrRemoved) revert AllowlistStateIdempotent(param.user, param.isEnabled);
|
|
181
|
+
emit BlacklistUpdated(param.user, param.isEnabled);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IAllowlist } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IAllowlist.sol";
|
|
5
|
+
import { AccessControl2StepUpgradeable } from "./../access/AccessControl2StepUpgradeable.sol";
|
|
6
|
+
import { AllowlistBaseUpgradeable } from "./AllowlistBaseUpgradeable.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title AllowlistRBACUpgradeable
|
|
10
|
+
* @author LayerZero Labs (tinom.eth)
|
|
11
|
+
* @custom:version 1.0.0
|
|
12
|
+
* @notice Abstract upgradeable contract that provides toggleable allowlist functionality between open, blacklist, and
|
|
13
|
+
* whitelist modes.
|
|
14
|
+
* @dev Exposes public management functions through `AccessControl2StepUpgradeable`.
|
|
15
|
+
*/
|
|
16
|
+
abstract contract AllowlistRBACUpgradeable is AllowlistBaseUpgradeable, AccessControl2StepUpgradeable {
|
|
17
|
+
/// @notice Role for setting the blacklist state for users.
|
|
18
|
+
bytes32 public constant BLACKLISTER_ROLE = keccak256("BLACKLISTER_ROLE");
|
|
19
|
+
|
|
20
|
+
/// @notice Role for setting the whitelist state for users.
|
|
21
|
+
bytes32 public constant WHITELISTER_ROLE = keccak256("WHITELISTER_ROLE");
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @notice Initializes the contract.
|
|
25
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
26
|
+
*/
|
|
27
|
+
function __AllowlistRBAC_init() internal onlyInitializing {}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @notice Unchained initialization function for the contract.
|
|
31
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
32
|
+
*/
|
|
33
|
+
function __AllowlistRBAC_init_unchained() internal onlyInitializing {}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @inheritdoc IAllowlist
|
|
37
|
+
*/
|
|
38
|
+
function setAllowlistMode(AllowlistMode _mode) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
39
|
+
_setAllowlistMode(_mode);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @inheritdoc IAllowlist
|
|
44
|
+
*/
|
|
45
|
+
function setBlacklisted(SetAllowlistParam[] calldata _params) public virtual onlyRole(BLACKLISTER_ROLE) {
|
|
46
|
+
_setBlacklisted(_params);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @inheritdoc IAllowlist
|
|
51
|
+
*/
|
|
52
|
+
function setWhitelisted(SetAllowlistParam[] calldata _params) public virtual onlyRole(WHITELISTER_ROLE) {
|
|
53
|
+
_setWhitelisted(_params);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IFeeHandler } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IFeeHandler.sol";
|
|
5
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @title FeeHandlerBaseUpgradeable
|
|
9
|
+
* @author LayerZero Labs (tinom.eth)
|
|
10
|
+
* @custom:version 1.0.0
|
|
11
|
+
* @notice Abstract upgradeable contract that stores the fee deposit address, for push-based fee handling.
|
|
12
|
+
* @dev Fee transfer logic is handled by the inheriting contract. This contract only manages the `feeDeposit` state.
|
|
13
|
+
* @dev No public management functions are exposed by this contract, wrappers should be used with access control.
|
|
14
|
+
* Alternatively, refer to `FeeHandlerRBACUpgradeable` for a permissioned implementation.
|
|
15
|
+
* @dev Does not include fee configuration (BPS / calculation). See `FeeConfigBaseUpgradeable` for that.
|
|
16
|
+
*/
|
|
17
|
+
abstract contract FeeHandlerBaseUpgradeable is IFeeHandler, Initializable {
|
|
18
|
+
/// @custom:storage-location erc7201:layerzerov2.storage.feehandler
|
|
19
|
+
struct FeeHandlerStorage {
|
|
20
|
+
address feeDeposit;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.feehandler")) - 1)) & ~bytes32(uint256(0xff))
|
|
24
|
+
bytes32 private constant FEE_HANDLER_STORAGE_LOCATION =
|
|
25
|
+
0xe32e0c5f1df3081ca85b86156deac82a46e8fb7b21b412e09f7ccdc5fca29900;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @notice Internal function to get the fee handler storage.
|
|
29
|
+
* @return $ Storage pointer
|
|
30
|
+
*/
|
|
31
|
+
function _getFeeHandlerStorage() internal pure returns (FeeHandlerStorage storage $) {
|
|
32
|
+
assembly {
|
|
33
|
+
$.slot := FEE_HANDLER_STORAGE_LOCATION
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @notice Initializes the contract with a fee deposit.
|
|
39
|
+
* @param _feeDeposit Address that will receive any accrued fees
|
|
40
|
+
*/
|
|
41
|
+
function __FeeHandlerBase_init(address _feeDeposit) internal onlyInitializing {
|
|
42
|
+
__FeeHandlerBase_init_unchained(_feeDeposit);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @notice Unchained initialization function for the contract.
|
|
47
|
+
* @param _feeDeposit Address that will receive any accrued fees
|
|
48
|
+
*/
|
|
49
|
+
function __FeeHandlerBase_init_unchained(address _feeDeposit) internal onlyInitializing {
|
|
50
|
+
_setFeeDeposit(_feeDeposit);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @inheritdoc IFeeHandler
|
|
55
|
+
*/
|
|
56
|
+
function feeDeposit() public view virtual returns (address deposit) {
|
|
57
|
+
return _getFeeHandlerStorage().feeDeposit;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @notice Sets the fee deposit address.
|
|
62
|
+
* @param _feeDeposit New fee deposit address
|
|
63
|
+
*/
|
|
64
|
+
function _setFeeDeposit(address _feeDeposit) internal virtual {
|
|
65
|
+
if (_feeDeposit == address(0)) revert InvalidFeeDeposit();
|
|
66
|
+
_getFeeHandlerStorage().feeDeposit = _feeDeposit;
|
|
67
|
+
emit FeeDepositSet(_feeDeposit);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IFeeHandler } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IFeeHandler.sol";
|
|
5
|
+
import { AccessControl2StepUpgradeable } from "./../access/AccessControl2StepUpgradeable.sol";
|
|
6
|
+
import { FeeHandlerBaseUpgradeable } from "./FeeHandlerBaseUpgradeable.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title FeeHandlerRBACUpgradeable
|
|
10
|
+
* @author LayerZero Labs (tinom.eth)
|
|
11
|
+
* @custom:version 1.0.0
|
|
12
|
+
* @notice Abstract upgradeable contract that stores the fee deposit address, for push-based fee handling.
|
|
13
|
+
* @dev Exposes public management functions through `AccessControl2StepUpgradeable`.
|
|
14
|
+
*/
|
|
15
|
+
abstract contract FeeHandlerRBACUpgradeable is FeeHandlerBaseUpgradeable, AccessControl2StepUpgradeable {
|
|
16
|
+
/**
|
|
17
|
+
* @notice Initializes the contract.
|
|
18
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
19
|
+
*/
|
|
20
|
+
function __FeeHandlerRBAC_init() internal onlyInitializing {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @notice Unchained initialization function for the contract.
|
|
24
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
25
|
+
*/
|
|
26
|
+
function __FeeHandlerRBAC_init_unchained() internal onlyInitializing {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @inheritdoc IFeeHandler
|
|
30
|
+
*/
|
|
31
|
+
function setFeeDeposit(address _feeDeposit) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
32
|
+
_setFeeDeposit(_feeDeposit);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IFeeConfig } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IFeeConfig.sol";
|
|
5
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @title FeeConfigBaseUpgradeable
|
|
9
|
+
* @author LayerZero Labs (@TRileySchwarz, tinom.eth)
|
|
10
|
+
* @custom:version 1.0.0
|
|
11
|
+
* @notice Abstract upgradeable contract that implements fee configuration and calculation.
|
|
12
|
+
* @dev No public management functions are exposed by this contract, wrappers should be used with access control.
|
|
13
|
+
* Alternatively, refer to `FeeConfigRBACUpgradeable` for a permissioned implementation.
|
|
14
|
+
* @dev Does not include fee receiver management. See `FeeHandlerBaseUpgradeable` for that.
|
|
15
|
+
*/
|
|
16
|
+
abstract contract FeeConfigBaseUpgradeable is IFeeConfig, Initializable {
|
|
17
|
+
/// @notice Constant with which fee basis points (BPS) are divided to get the fee amount.
|
|
18
|
+
uint16 public constant BPS_DENOMINATOR = 10_000;
|
|
19
|
+
|
|
20
|
+
/// @custom:storage-location erc7201:layerzerov2.storage.feeconfig
|
|
21
|
+
struct FeeConfigStorage {
|
|
22
|
+
uint16 defaultFeeBps;
|
|
23
|
+
mapping(uint256 id => FeeConfig config) feeBps;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.feeconfig")) - 1)) & ~bytes32(uint256(0xff))
|
|
27
|
+
bytes32 private constant FEE_CONFIG_STORAGE_LOCATION =
|
|
28
|
+
0x19c40dd5c7b9d6e4dbe259e67955cccfb75eaf6c218fbfbd413bfcd8248dd800;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @notice Internal function to get the fee config storage.
|
|
32
|
+
* @return $ Storage pointer
|
|
33
|
+
*/
|
|
34
|
+
function _getFeeConfigStorage() internal pure returns (FeeConfigStorage storage $) {
|
|
35
|
+
assembly {
|
|
36
|
+
$.slot := FEE_CONFIG_STORAGE_LOCATION
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @notice Initializes the contract.
|
|
42
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
43
|
+
*/
|
|
44
|
+
function __FeeConfigBase_init() internal onlyInitializing {}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @notice Unchained initialization function for the contract.
|
|
48
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
49
|
+
*/
|
|
50
|
+
function __FeeConfigBase_init_unchained() internal onlyInitializing {}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @inheritdoc IFeeConfig
|
|
54
|
+
*/
|
|
55
|
+
function getFee(uint256 _id, uint256 _amount) public view virtual returns (uint256 fee) {
|
|
56
|
+
uint16 bps = _getFeeBps(_id);
|
|
57
|
+
/// @dev If `amount * bps < BPS_DENOMINATOR`, there is no fee.
|
|
58
|
+
return bps == 0 ? 0 : (_amount * bps) / BPS_DENOMINATOR;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @inheritdoc IFeeConfig
|
|
63
|
+
*/
|
|
64
|
+
function getAmountBeforeFee(
|
|
65
|
+
uint256 _id,
|
|
66
|
+
uint256 _amountAfterFee
|
|
67
|
+
) public view virtual returns (uint256 amountBeforeFee) {
|
|
68
|
+
uint16 bps = _getFeeBps(_id);
|
|
69
|
+
if (bps == BPS_DENOMINATOR) return 0;
|
|
70
|
+
if (bps == 0) return _amountAfterFee;
|
|
71
|
+
return (_amountAfterFee * BPS_DENOMINATOR) / (BPS_DENOMINATOR - bps);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @inheritdoc IFeeConfig
|
|
76
|
+
*/
|
|
77
|
+
function defaultFeeBps() public view virtual returns (uint16 fee) {
|
|
78
|
+
FeeConfigStorage storage $ = _getFeeConfigStorage();
|
|
79
|
+
return $.defaultFeeBps;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @inheritdoc IFeeConfig
|
|
84
|
+
*/
|
|
85
|
+
function feeBps(uint256 _id) public view virtual returns (FeeConfig memory config) {
|
|
86
|
+
FeeConfigStorage storage $ = _getFeeConfigStorage();
|
|
87
|
+
return $.feeBps[_id];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @notice Retrieves the fee basis points (BPS) for a specific destination ID.
|
|
92
|
+
* @param _id Destination ID
|
|
93
|
+
* @return bps Fee basis points (BPS) for the destination ID
|
|
94
|
+
*/
|
|
95
|
+
function _getFeeBps(uint256 _id) internal view virtual returns (uint16) {
|
|
96
|
+
FeeConfigStorage storage $ = _getFeeConfigStorage();
|
|
97
|
+
FeeConfig storage config = $.feeBps[_id];
|
|
98
|
+
return config.enabled ? config.feeBps : $.defaultFeeBps;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============ Internal Functions to Wrap with Access Control ============
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @notice Internal function to set the default fee basis points (BPS) for all destinations.
|
|
105
|
+
* @dev To be wrapped with access control.
|
|
106
|
+
* @param _feeBps New default fee basis points (BPS)
|
|
107
|
+
*/
|
|
108
|
+
function _setDefaultFeeBps(uint16 _feeBps) internal virtual {
|
|
109
|
+
if (_feeBps > BPS_DENOMINATOR) revert IFeeConfig.InvalidBps(_feeBps);
|
|
110
|
+
FeeConfigStorage storage $ = _getFeeConfigStorage();
|
|
111
|
+
$.defaultFeeBps = _feeBps;
|
|
112
|
+
emit DefaultFeeBpsSet(_feeBps);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @notice Internal function to set the fee basis points (BPS) for a specific destination ID.
|
|
117
|
+
* @dev To be wrapped with access control.
|
|
118
|
+
* @param _id Destination ID
|
|
119
|
+
* @param _feeBps New fee basis points (BPS)
|
|
120
|
+
* @param _enabled Whether the fee is enabled for the destination
|
|
121
|
+
*/
|
|
122
|
+
function _setFeeBps(uint256 _id, uint16 _feeBps, bool _enabled) internal virtual {
|
|
123
|
+
if (_feeBps > BPS_DENOMINATOR) revert IFeeConfig.InvalidBps(_feeBps);
|
|
124
|
+
FeeConfigStorage storage $ = _getFeeConfigStorage();
|
|
125
|
+
$.feeBps[_id] = FeeConfig(_feeBps, _enabled);
|
|
126
|
+
emit FeeBpsSet(_id, _feeBps, _enabled);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IFeeConfig } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IFeeConfig.sol";
|
|
5
|
+
import { AccessControl2StepUpgradeable } from "./../access/AccessControl2StepUpgradeable.sol";
|
|
6
|
+
import { FeeConfigBaseUpgradeable } from "./FeeConfigBaseUpgradeable.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title FeeConfigRBACUpgradeable
|
|
10
|
+
* @author LayerZero Labs (@TRileySchwarz, tinom.eth)
|
|
11
|
+
* @custom:version 1.0.0
|
|
12
|
+
* @notice Abstract upgradeable contract that implements fee configuration and calculation.
|
|
13
|
+
* @dev Exposes public management functions through `AccessControl2StepUpgradeable`.
|
|
14
|
+
*/
|
|
15
|
+
abstract contract FeeConfigRBACUpgradeable is FeeConfigBaseUpgradeable, AccessControl2StepUpgradeable {
|
|
16
|
+
/// @notice Role for setting fee basis points.
|
|
17
|
+
bytes32 public constant FEE_CONFIG_MANAGER_ROLE = keccak256("FEE_CONFIG_MANAGER_ROLE");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @notice Initializes the contract.
|
|
21
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
22
|
+
*/
|
|
23
|
+
function __FeeConfigRBAC_init() internal onlyInitializing {}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @notice Unchained initialization function for the contract.
|
|
27
|
+
* @dev This function is empty on purpose, as no custom logic is needed.
|
|
28
|
+
*/
|
|
29
|
+
function __FeeConfigRBAC_init_unchained() internal onlyInitializing {}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @inheritdoc IFeeConfig
|
|
33
|
+
*/
|
|
34
|
+
function setDefaultFeeBps(uint16 _feeBps) public virtual onlyRole(FEE_CONFIG_MANAGER_ROLE) {
|
|
35
|
+
_setDefaultFeeBps(_feeBps);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @inheritdoc IFeeConfig
|
|
40
|
+
*/
|
|
41
|
+
function setFeeBps(uint256 _id, uint16 _feeBps, bool _enabled) public virtual onlyRole(FEE_CONFIG_MANAGER_ROLE) {
|
|
42
|
+
_setFeeBps(_id, _feeBps, _enabled);
|
|
43
|
+
}
|
|
44
|
+
}
|