@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.
Files changed (37) hide show
  1. package/.turbo/turbo-lint.log +491 -0
  2. package/.turbo/turbo-test.log +1356 -0
  3. package/LICENSE +23 -0
  4. package/contracts/access/AccessControl2StepUpgradeable.sol +144 -0
  5. package/contracts/allowlist/AllowlistBaseUpgradeable.sol +184 -0
  6. package/contracts/allowlist/AllowlistRBACUpgradeable.sol +55 -0
  7. package/contracts/fee-accounting/FeeHandlerBaseUpgradeable.sol +69 -0
  8. package/contracts/fee-accounting/FeeHandlerRBACUpgradeable.sol +34 -0
  9. package/contracts/fee-config/FeeConfigBaseUpgradeable.sol +128 -0
  10. package/contracts/fee-config/FeeConfigRBACUpgradeable.sol +44 -0
  11. package/contracts/libs/EnumerableSetPagination.sol +77 -0
  12. package/contracts/pause/PauseBaseUpgradeable.sol +107 -0
  13. package/contracts/pause/PauseRBACUpgradeable.sol +47 -0
  14. package/contracts/pause-by-id/PauseByIDBaseUpgradeable.sol +127 -0
  15. package/contracts/pause-by-id/PauseByIDRBACUpgradeable.sol +74 -0
  16. package/contracts/rate-limiter/RateLimiterBaseUpgradeable.sol +636 -0
  17. package/contracts/rate-limiter/RateLimiterRBACUpgradeable.sol +89 -0
  18. package/contracts/rate-limiter/libs/RateLimiterUtils.sol +82 -0
  19. package/foundry.toml +27 -0
  20. package/package.json +34 -0
  21. package/solhint.config.js +3 -0
  22. package/test/AccessControl2StepUpgradeable.t.sol +374 -0
  23. package/test/AllowlistBaseUpgradeable.t.sol +380 -0
  24. package/test/AllowlistRBACUpgradeable.t.sol +84 -0
  25. package/test/EnumerableSetPagination.t.sol +445 -0
  26. package/test/FeeConfigBaseUpgradeable.t.sol +232 -0
  27. package/test/FeeConfigRBACUpgradeable.t.sol +59 -0
  28. package/test/FeeHandlerBaseUpgradeable.t.sol +78 -0
  29. package/test/FeeHandlerRBACUpgradeable.t.sol +45 -0
  30. package/test/PauseBaseUpgradeable.t.sol +244 -0
  31. package/test/PauseByIDBaseUpgradeable.t.sol +337 -0
  32. package/test/PauseByIDRBACUpgradeable.t.sol +414 -0
  33. package/test/PauseRBACUpgradeable.t.sol +258 -0
  34. package/test/RateLimiterBaseUpgradeable.t.sol +826 -0
  35. package/test/RateLimiterRBACUpgradeable.t.sol +128 -0
  36. package/test/RateLimiterRBACUpgradeableInvariant.t.sol +444 -0
  37. package/test/RateLimiterUtils.t.sol +137 -0
@@ -0,0 +1,77 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.22;
3
+
4
+ import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
5
+
6
+ /**
7
+ * @title EnumerableSetPagination
8
+ * @author LayerZero Labs (tinom.eth)
9
+ * @custom:version 1.0.0
10
+ * @notice Library providing pagination utilities for `EnumerableSet.AddressSet` and `EnumerableSet.UintSet`.
11
+ */
12
+ library EnumerableSetPagination {
13
+ using EnumerableSet for EnumerableSet.AddressSet;
14
+ using EnumerableSet for EnumerableSet.UintSet;
15
+
16
+ /**
17
+ * @notice Returns a paginated subset of addresses from an `EnumerableSet`.
18
+ * @param _set `EnumerableSet.AddressSet` to paginate
19
+ * @param _offset Starting index
20
+ * @param _limit Maximum number of addresses to return
21
+ * @return addresses Array of addresses in the specified range
22
+ */
23
+ function paginate(
24
+ EnumerableSet.AddressSet storage _set,
25
+ uint256 _offset,
26
+ uint256 _limit
27
+ ) internal view returns (address[] memory addresses) {
28
+ uint256 total = _set.length();
29
+
30
+ if (_offset >= total) {
31
+ return new address[](0);
32
+ }
33
+
34
+ uint256 end = _offset + _limit;
35
+ if (end > total) {
36
+ end = total;
37
+ }
38
+
39
+ uint256 resultLength = end - _offset;
40
+ addresses = new address[](resultLength);
41
+
42
+ for (uint256 i = 0; i < resultLength; i++) {
43
+ addresses[i] = _set.at(_offset + i);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * @notice Returns a paginated subset of `uint256` values from an `EnumerableSet`.
49
+ * @param _set `EnumerableSet.UintSet` to paginate
50
+ * @param _offset Starting index
51
+ * @param _limit Maximum number of values to return
52
+ * @return values Array of `uint256` values in the specified range
53
+ */
54
+ function paginate(
55
+ EnumerableSet.UintSet storage _set,
56
+ uint256 _offset,
57
+ uint256 _limit
58
+ ) internal view returns (uint256[] memory values) {
59
+ uint256 total = _set.length();
60
+
61
+ if (_offset >= total) {
62
+ return new uint256[](0);
63
+ }
64
+
65
+ uint256 end = _offset + _limit;
66
+ if (end > total) {
67
+ end = total;
68
+ }
69
+
70
+ uint256 resultLength = end - _offset;
71
+ values = new uint256[](resultLength);
72
+
73
+ for (uint256 i = 0; i < resultLength; i++) {
74
+ values[i] = _set.at(_offset + i);
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,107 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.22;
3
+
4
+ import { IPause } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPause.sol";
5
+ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6
+
7
+ /**
8
+ * @title PauseBaseUpgradeable
9
+ * @author LayerZero Labs (tinom.eth)
10
+ * @custom:version 1.0.0
11
+ * @notice Abstract upgradeable contract that implements pause configuration and enforcement.
12
+ * @dev No public management functions are exposed by this contract, wrappers should be used with access control.
13
+ * Alternatively, refer to `PauseRBACUpgradeable` for a permissioned implementation.
14
+ */
15
+ abstract contract PauseBaseUpgradeable is IPause, Initializable {
16
+ /// @custom:storage-location erc7201:layerzerov2.storage.pause
17
+ struct PauseStorage {
18
+ bool paused;
19
+ }
20
+
21
+ // keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.pause")) - 1)) & ~bytes32(uint256(0xff))
22
+ bytes32 private constant PAUSE_STORAGE_LOCATION =
23
+ 0x27be0a968b102c71096101138efa2fc0db00aea7b287f10fdc298bfd2d4ec000;
24
+
25
+ /**
26
+ * @notice Internal function to get the pause storage.
27
+ * @return $ Storage pointer
28
+ */
29
+ function _getPauseStorage() internal pure returns (PauseStorage storage $) {
30
+ assembly {
31
+ $.slot := PAUSE_STORAGE_LOCATION
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @notice Initializes the contract.
37
+ * @dev This function is empty on purpose, as no custom logic is needed.
38
+ */
39
+ function __PauseBase_init() internal onlyInitializing {}
40
+
41
+ /**
42
+ * @notice Unchained initialization function for the contract.
43
+ * @dev This function is empty on purpose, as no custom logic is needed.
44
+ */
45
+ function __PauseBase_init_unchained() internal onlyInitializing {}
46
+
47
+ /**
48
+ * @notice Modifier that reverts if the system is paused.
49
+ */
50
+ modifier whenNotPaused() {
51
+ if (_getPaused()) revert Paused();
52
+ _;
53
+ }
54
+
55
+ /**
56
+ * @inheritdoc IPause
57
+ */
58
+ function isPaused() public view virtual returns (bool paused) {
59
+ return _getPaused();
60
+ }
61
+
62
+ /**
63
+ * @notice Retrieves the pause status.
64
+ * @return paused Whether the system is paused
65
+ */
66
+ function _getPaused() internal view virtual returns (bool) {
67
+ PauseStorage storage $ = _getPauseStorage();
68
+ return $.paused;
69
+ }
70
+
71
+ /**
72
+ * @notice Enforces that the system is not paused.
73
+ * @dev Reverts with `Paused` error if the system is paused.
74
+ */
75
+ function _assertNotPaused() internal view virtual {
76
+ if (_getPaused()) revert Paused();
77
+ }
78
+
79
+ /**
80
+ * @notice Internal function to set the pause status.
81
+ * @param _paused New pause status
82
+ */
83
+ function _setPaused(bool _paused) internal virtual {
84
+ PauseStorage storage $ = _getPauseStorage();
85
+ if ($.paused == _paused) revert PauseStateIdempotent(_paused);
86
+ $.paused = _paused;
87
+ emit PauseSet(_paused);
88
+ }
89
+
90
+ // ============ Internal Functions to Wrap with Access Control ============
91
+
92
+ /**
93
+ * @notice Internal function to set the pause status to true.
94
+ * @dev To be wrapped with access control.
95
+ */
96
+ function _pause() internal virtual {
97
+ _setPaused(true);
98
+ }
99
+
100
+ /**
101
+ * @notice Internal function to set the pause status to false.
102
+ * @dev To be wrapped with access control.
103
+ */
104
+ function _unpause() internal virtual {
105
+ _setPaused(false);
106
+ }
107
+ }
@@ -0,0 +1,47 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.22;
3
+
4
+ import { IPause } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPause.sol";
5
+ import { AccessControl2StepUpgradeable } from "./../access/AccessControl2StepUpgradeable.sol";
6
+ import { PauseBaseUpgradeable } from "./PauseBaseUpgradeable.sol";
7
+
8
+ /**
9
+ * @title PauseRBACUpgradeable
10
+ * @author LayerZero Labs (tinom.eth)
11
+ * @custom:version 1.0.0
12
+ * @notice Abstract upgradeable contract that provides pause functionality.
13
+ * @dev Exposes public management functions through `AccessControl2StepUpgradeable`.
14
+ */
15
+ abstract contract PauseRBACUpgradeable is PauseBaseUpgradeable, AccessControl2StepUpgradeable {
16
+ /// @notice Role for pausing the contract.
17
+ bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
18
+
19
+ /// @notice Role for unpausing the contract.
20
+ bytes32 public constant UNPAUSER_ROLE = keccak256("UNPAUSER_ROLE");
21
+
22
+ /**
23
+ * @notice Initializes the contract.
24
+ * @dev This function is empty on purpose, as no custom logic is needed.
25
+ */
26
+ function __PauseRBAC_init() internal onlyInitializing {}
27
+
28
+ /**
29
+ * @notice Unchained initialization function for the contract.
30
+ * @dev This function is empty on purpose, as no custom logic is needed.
31
+ */
32
+ function __PauseRBAC_init_unchained() internal onlyInitializing {}
33
+
34
+ /**
35
+ * @inheritdoc IPause
36
+ */
37
+ function pause() public virtual onlyRole(PAUSER_ROLE) {
38
+ _pause();
39
+ }
40
+
41
+ /**
42
+ * @inheritdoc IPause
43
+ */
44
+ function unpause() public virtual onlyRole(UNPAUSER_ROLE) {
45
+ _unpause();
46
+ }
47
+ }
@@ -0,0 +1,127 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.22;
3
+
4
+ import { IPauseByID } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPauseByID.sol";
5
+ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6
+
7
+ /**
8
+ * @title PauseByIDBaseUpgradeable
9
+ * @author LayerZero Labs (tinom.eth)
10
+ * @custom:version 1.0.0
11
+ * @notice Abstract upgradeable contract that implements pause configuration and enforcement per ID.
12
+ * @dev No public management functions are exposed by this contract, wrappers should be used with access control.
13
+ * Alternatively, refer to `PauseByIDRBACUpgradeable` for a permissioned implementation.
14
+ */
15
+ abstract contract PauseByIDBaseUpgradeable is IPauseByID, Initializable {
16
+ /// @custom:storage-location erc7201:layerzerov2.storage.pausebyid
17
+ struct PauseByIDStorage {
18
+ bool defaultPaused;
19
+ mapping(uint256 id => PauseConfig config) pauseConfigs;
20
+ }
21
+
22
+ // keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.pausebyid")) - 1)) & ~bytes32(uint256(0xff))
23
+ bytes32 private constant PAUSE_BY_ID_STORAGE_LOCATION =
24
+ 0xac2cb783706dc5ac6b91d3675ceaddc73634a37f082a72b77dcdd25ee1f51300;
25
+
26
+ /**
27
+ * @notice Internal function to get the pause storage.
28
+ * @return $ Storage pointer
29
+ */
30
+ function _getPauseByIDStorage() internal pure returns (PauseByIDStorage storage $) {
31
+ assembly {
32
+ $.slot := PAUSE_BY_ID_STORAGE_LOCATION
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @notice Initializes the contract.
38
+ * @dev This function is empty on purpose, as no custom logic is needed.
39
+ */
40
+ function __PauseByIDBase_init() internal onlyInitializing {}
41
+
42
+ /**
43
+ * @notice Unchained initialization function for the contract.
44
+ * @dev This function is empty on purpose, as no custom logic is needed.
45
+ */
46
+ function __PauseByIDBase_init_unchained() internal onlyInitializing {}
47
+
48
+ /**
49
+ * @notice Modifier that reverts if the destination ID is paused.
50
+ * @param _id Destination ID
51
+ */
52
+ modifier whenNotPaused(uint256 _id) {
53
+ if (_getPaused(_id)) revert Paused(_id);
54
+ _;
55
+ }
56
+
57
+ /**
58
+ * @inheritdoc IPauseByID
59
+ */
60
+ function isPaused(uint256 _id) public view virtual returns (bool paused) {
61
+ return _getPaused(_id);
62
+ }
63
+
64
+ /**
65
+ * @inheritdoc IPauseByID
66
+ */
67
+ function defaultPaused() public view virtual returns (bool paused) {
68
+ PauseByIDStorage storage $ = _getPauseByIDStorage();
69
+ return $.defaultPaused;
70
+ }
71
+
72
+ /**
73
+ * @inheritdoc IPauseByID
74
+ */
75
+ function pauseConfig(uint256 _id) public view virtual returns (PauseConfig memory config) {
76
+ PauseByIDStorage storage $ = _getPauseByIDStorage();
77
+ return $.pauseConfigs[_id];
78
+ }
79
+
80
+ /**
81
+ * @notice Retrieves the pause status for a specific destination ID.
82
+ * @param _id Destination ID
83
+ * @return paused Whether transfers are paused for the destination ID
84
+ */
85
+ function _getPaused(uint256 _id) internal view virtual returns (bool) {
86
+ PauseByIDStorage storage $ = _getPauseByIDStorage();
87
+ PauseConfig storage config = $.pauseConfigs[_id];
88
+ return config.enabled ? config.paused : $.defaultPaused;
89
+ }
90
+
91
+ /**
92
+ * @notice Enforces that transfers to a destination ID are not paused.
93
+ * @dev Reverts with `Paused` error if the destination is paused.
94
+ * @param _id Destination ID
95
+ */
96
+ function _assertNotPaused(uint256 _id) internal view virtual {
97
+ if (_getPaused(_id)) revert Paused(_id);
98
+ }
99
+
100
+ // ============ Internal Functions to Wrap with Access Control ============
101
+
102
+ /**
103
+ * @notice Internal function to set the default pause status for all destinations.
104
+ * @dev To be wrapped with access control.
105
+ * @param _paused New default pause status
106
+ */
107
+ function _setDefaultPaused(bool _paused) internal virtual {
108
+ PauseByIDStorage storage $ = _getPauseByIDStorage();
109
+ if ($.defaultPaused == _paused) revert PauseStateIdempotent(_paused);
110
+ $.defaultPaused = _paused;
111
+ emit DefaultPauseSet(_paused);
112
+ }
113
+
114
+ /**
115
+ * @notice Internal function to set the pause status for an array of destination IDs.
116
+ * @dev To be wrapped with access control.
117
+ * @param _params Array of pause configurations
118
+ */
119
+ function _setPaused(SetPausedParam[] calldata _params) internal virtual {
120
+ PauseByIDStorage storage $ = _getPauseByIDStorage();
121
+ for (uint256 i = 0; i < _params.length; i++) {
122
+ SetPausedParam calldata param = _params[i];
123
+ $.pauseConfigs[param.id] = PauseConfig(param.paused, param.enabled);
124
+ emit PauseSet(param.id, param.paused, param.enabled);
125
+ }
126
+ }
127
+ }
@@ -0,0 +1,74 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.22;
3
+
4
+ import { IPauseByID } from "@layerzerolabs/utils-evm-contracts/contracts/interfaces/IPauseByID.sol";
5
+ import { AccessControl2StepUpgradeable } from "./../access/AccessControl2StepUpgradeable.sol";
6
+ import { PauseByIDBaseUpgradeable } from "./PauseByIDBaseUpgradeable.sol";
7
+
8
+ /**
9
+ * @title PauseByIDRBACUpgradeable
10
+ * @author LayerZero Labs (tinom.eth)
11
+ * @custom:version 1.0.0
12
+ * @notice Abstract upgradeable contract that implements pause configuration and enforcement per ID.
13
+ * @dev Exposes public management functions through `AccessControl2StepUpgradeable`.
14
+ */
15
+ abstract contract PauseByIDRBACUpgradeable is PauseByIDBaseUpgradeable, AccessControl2StepUpgradeable {
16
+ /// @notice Role for pausing the contract.
17
+ bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
18
+
19
+ /// @notice Role for unpausing the contract.
20
+ bytes32 public constant UNPAUSER_ROLE = keccak256("UNPAUSER_ROLE");
21
+
22
+ /**
23
+ * @notice Initializes the contract.
24
+ * @dev This function is empty on purpose, as no custom logic is needed.
25
+ */
26
+ function __PauseByIDRBAC_init() internal onlyInitializing {}
27
+
28
+ /**
29
+ * @notice Unchained initialization function for the contract.
30
+ * @dev This function is empty on purpose, as no custom logic is needed.
31
+ */
32
+ function __PauseByIDRBAC_init_unchained() internal onlyInitializing {}
33
+
34
+ /**
35
+ * @inheritdoc IPauseByID
36
+ */
37
+ function setDefaultPaused(bool _paused) public virtual {
38
+ _paused ? _checkRole(PAUSER_ROLE) : _checkRole(UNPAUSER_ROLE);
39
+ _setDefaultPaused(_paused);
40
+ }
41
+
42
+ /**
43
+ * @dev Caller must have both `PAUSER_ROLE` and `UNPAUSER_ROLE` if setting mixed pause states.
44
+ * Role checks are based on the effective pause state, accounting for the `enabled` flag and `defaultPaused`
45
+ * fallback.
46
+ * @dev Requires the more restrictive `UNPAUSER_ROLE` for no-ops.
47
+ * @inheritdoc IPauseByID
48
+ */
49
+ function setPaused(SetPausedParam[] calldata _params) public virtual {
50
+ bool needsPauser;
51
+ bool needsUnpauser;
52
+ bool _defaultPaused = defaultPaused();
53
+
54
+ for (uint256 i = 0; i < _params.length; i++) {
55
+ /// @dev Determine if the operation effectively pauses or unpauses the ID.
56
+ /// It's safe to ignore `_params[i].paused` if the ID is not enabled, since it'll be ignored and this
57
+ /// function is the entrypoint for ID configuration, which disallows privilege escalation.
58
+ if (_params[i].enabled ? _params[i].paused : _defaultPaused) {
59
+ needsPauser = true;
60
+ } else {
61
+ needsUnpauser = true;
62
+ }
63
+
64
+ /// @dev Early exit if both roles are needed.
65
+ if (needsPauser && needsUnpauser) break;
66
+ }
67
+
68
+ if (needsPauser) _checkRole(PAUSER_ROLE);
69
+ /// @dev Avoid unauthorized no-ops.
70
+ if (needsUnpauser || !needsPauser) _checkRole(UNPAUSER_ROLE);
71
+
72
+ _setPaused(_params);
73
+ }
74
+ }