@layerzerolabs/oapp-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 +216 -0
- package/.turbo/turbo-test.log +124 -0
- package/LICENSE +23 -0
- package/contracts/oapp/OAppCoreBaseUpgradeable.sol +111 -0
- package/contracts/oapp/OAppCoreRBACUpgradeable.sol +71 -0
- package/contracts/oapp/OAppReceiverUpgradeable.sol +135 -0
- package/contracts/oapp/OAppSenderUpgradeable.sol +141 -0
- package/contracts/oapp/OAppUpgradeable.sol +51 -0
- package/contracts/oapp/alt/OAppAltUpgradeable.sol +48 -0
- package/contracts/oapp/msg-inspection/OAppMsgInspectionBaseUpgradeable.sol +67 -0
- package/contracts/oapp/msg-inspection/OAppMsgInspectionRBACUpgradeable.sol +34 -0
- package/contracts/oapp/options-type-3/OAppOptionsType3BaseUpgradeable.sol +126 -0
- package/contracts/oapp/options-type-3/OAppOptionsType3RBACUpgradeable.sol +36 -0
- package/foundry.toml +20 -0
- package/package.json +42 -0
- package/solhint.config.js +3 -0
- package/test/OAppAltUpgradeable.t.sol +130 -0
- package/test/OAppCoreRBACUpgradeable.t.sol +115 -0
- package/test/OAppOptionsType3BaseUpgradeable.t.sol +239 -0
- package/test/OAppOptionsType3RBACUpgradeable.t.sol +67 -0
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@layerzerolabs/oapp-upgradeable-evm-contracts",
|
|
3
|
+
"version": "0.2.74",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "LayerZero Labs reference EVM upgradeable OApp implementation",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@layerzerolabs/lz-evm-messagelib-v2": "3.0.167",
|
|
9
|
+
"@layerzerolabs/lz-evm-protocol-v2": "3.0.167",
|
|
10
|
+
"@layerzerolabs/lz-evm-v1-0.7": "3.0.167",
|
|
11
|
+
"@layerzerolabs/test-devtools-evm-foundry": "8.0.1",
|
|
12
|
+
"@layerzerolabs/toolbox-foundry": "^0.1.13",
|
|
13
|
+
"@openzeppelin/contracts": "^5.0.2",
|
|
14
|
+
"@openzeppelin/contracts-upgradeable": "^5.0.2",
|
|
15
|
+
"ethers": "^5.8.0",
|
|
16
|
+
"solhint": "^6.0.1",
|
|
17
|
+
"solidity-bytes-utils": "^0.8.4",
|
|
18
|
+
"@layerzerolabs/oapp-evm-contracts": "0.2.74",
|
|
19
|
+
"@layerzerolabs/typescript-configuration": "0.2.74",
|
|
20
|
+
"@layerzerolabs/tsup-configuration": "0.2.74",
|
|
21
|
+
"@layerzerolabs/solhint-configuration": "0.2.74",
|
|
22
|
+
"@layerzerolabs/test-utils-evm-contracts": "0.2.74",
|
|
23
|
+
"@layerzerolabs/utils-evm-contracts": "0.2.74",
|
|
24
|
+
"@layerzerolabs/utils-upgradeable-evm-contracts": "0.2.74",
|
|
25
|
+
"@layerzerolabs/vm-tooling-evm": "0.2.74"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "restricted",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
31
|
+
"externalRepoConfig": {
|
|
32
|
+
"targets": [
|
|
33
|
+
"audit-external",
|
|
34
|
+
"monorepo-external"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"clean-artifacts": "rm -rf artifacts* cache hh-cache*",
|
|
39
|
+
"lint": "solhint --config solhint.config.js 'contracts/**/*.sol' 'test/**/*.sol' --fix --noPrompt",
|
|
40
|
+
"test": "pnpm lz-tool forge test"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IOAppAlt } from "@layerzerolabs/oapp-evm-contracts/contracts/interfaces/IOAppAlt.sol";
|
|
5
|
+
import { EndpointV2AltMock } from "@layerzerolabs/test-devtools-evm-foundry/contracts/mocks/EndpointV2AltMock.sol";
|
|
6
|
+
import { TestHelperOz5 } from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol";
|
|
7
|
+
import { MockERC20 } from "@layerzerolabs/test-utils-evm-contracts/contracts/mocks/MockERC20.sol";
|
|
8
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
9
|
+
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
10
|
+
import { OAppAltUpgradeable } from "./../contracts/oapp/alt/OAppAltUpgradeable.sol";
|
|
11
|
+
import { OAppCoreBaseUpgradeable } from "./../contracts/oapp/OAppCoreBaseUpgradeable.sol";
|
|
12
|
+
|
|
13
|
+
contract OAppAltUpgradeableHarness is OAppCoreBaseUpgradeable, OAppAltUpgradeable {
|
|
14
|
+
constructor(address _endpoint) OAppCoreBaseUpgradeable(_endpoint) {}
|
|
15
|
+
|
|
16
|
+
function initialize(address _delegate) public initializer {
|
|
17
|
+
__OAppCoreBase_init(_delegate);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function oAppVersion() public pure returns (uint64 senderVersion, uint64 receiverVersion) {
|
|
21
|
+
return (1, 1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function payNative(uint256 _nativeFee) public payable returns (uint256 nativeFee) {
|
|
25
|
+
return _payNative(_nativeFee);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _payNative(uint256 _nativeFee) internal virtual override(OAppAltUpgradeable) returns (uint256 nativeFee) {
|
|
29
|
+
return OAppAltUpgradeable._payNative(_nativeFee);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function setPeer(uint32 _eid, bytes32 _peer) external {
|
|
33
|
+
_setPeer(_eid, _peer);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function setDelegate(address _delegate) external {
|
|
37
|
+
_setDelegate(_delegate);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
contract OAppAltUpgradeableTest is TestHelperOz5 {
|
|
42
|
+
OAppAltUpgradeableHarness impl;
|
|
43
|
+
OAppAltUpgradeableHarness oapp;
|
|
44
|
+
MockERC20 nativeToken;
|
|
45
|
+
address endpoint;
|
|
46
|
+
|
|
47
|
+
address delegate = makeAddr("delegate");
|
|
48
|
+
address alice = makeAddr("alice");
|
|
49
|
+
address bob = makeAddr("bob");
|
|
50
|
+
|
|
51
|
+
function setUp() public override {
|
|
52
|
+
nativeToken = new MockERC20(18);
|
|
53
|
+
|
|
54
|
+
address[] memory nativeTokenAddrs = new address[](2);
|
|
55
|
+
nativeTokenAddrs[0] = address(nativeToken);
|
|
56
|
+
createEndpoints(2, LibraryType.SimpleMessageLib, nativeTokenAddrs);
|
|
57
|
+
endpoint = address(endpointSetup.endpointList[0]);
|
|
58
|
+
|
|
59
|
+
impl = new OAppAltUpgradeableHarness(endpoint);
|
|
60
|
+
|
|
61
|
+
bytes memory initData = abi.encodeWithSelector(OAppAltUpgradeableHarness.initialize.selector, delegate);
|
|
62
|
+
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(address(impl), delegate, initData);
|
|
63
|
+
|
|
64
|
+
oapp = OAppAltUpgradeableHarness(address(proxy));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function test_constructor() public view {
|
|
68
|
+
assertEq(address(oapp.endpoint()), endpoint);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function test_constructor_Revert_InvalidNativeToken() public {
|
|
72
|
+
EndpointV2AltMock endpointZeroNative = new EndpointV2AltMock(1, address(this), address(0));
|
|
73
|
+
|
|
74
|
+
vm.expectRevert(IOAppAlt.InvalidNativeToken.selector);
|
|
75
|
+
new OAppAltUpgradeableHarness(address(endpointZeroNative));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function test_payNative() public {
|
|
79
|
+
uint256 fee = 0.1 ether;
|
|
80
|
+
nativeToken.mint(alice, fee);
|
|
81
|
+
|
|
82
|
+
vm.startPrank(alice);
|
|
83
|
+
nativeToken.approve(address(oapp), fee);
|
|
84
|
+
|
|
85
|
+
uint256 returnedFee = oapp.payNative(fee);
|
|
86
|
+
vm.stopPrank();
|
|
87
|
+
|
|
88
|
+
assertEq(returnedFee, 0, "Should return 0 as fee is paid via ERC20");
|
|
89
|
+
assertEq(nativeToken.balanceOf(alice), 0, "Alice should have 0 balance");
|
|
90
|
+
assertEq(nativeToken.balanceOf(endpoint), fee, "Endpoint should have the fee");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function test_payNative_ZeroFee() public {
|
|
94
|
+
/// @dev Expects `transferFrom` to never be called on the native token.
|
|
95
|
+
vm.expectCall(address(nativeToken), abi.encodeWithSelector(IERC20.transferFrom.selector), 0);
|
|
96
|
+
|
|
97
|
+
vm.prank(alice);
|
|
98
|
+
uint256 returnedFee = oapp.payNative(0);
|
|
99
|
+
|
|
100
|
+
assertEq(returnedFee, 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function test_payNative_Revert_OnlyAltToken() public {
|
|
104
|
+
uint256 fee = 0.1 ether;
|
|
105
|
+
nativeToken.mint(alice, fee);
|
|
106
|
+
vm.deal(alice, 1 wei);
|
|
107
|
+
|
|
108
|
+
vm.startPrank(alice);
|
|
109
|
+
nativeToken.approve(address(oapp), fee);
|
|
110
|
+
|
|
111
|
+
vm.expectRevert(IOAppAlt.OnlyAltToken.selector);
|
|
112
|
+
oapp.payNative{ value: 1 wei }(fee);
|
|
113
|
+
vm.stopPrank();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function test_payNative_Fuzz(uint96 _fee) public {
|
|
117
|
+
_fee = uint96(bound(_fee, 1, 1_000_000 ether));
|
|
118
|
+
nativeToken.mint(alice, _fee);
|
|
119
|
+
|
|
120
|
+
vm.startPrank(alice);
|
|
121
|
+
nativeToken.approve(address(oapp), _fee);
|
|
122
|
+
|
|
123
|
+
uint256 returnedFee = oapp.payNative(_fee);
|
|
124
|
+
vm.stopPrank();
|
|
125
|
+
|
|
126
|
+
assertEq(returnedFee, 0);
|
|
127
|
+
assertEq(nativeToken.balanceOf(alice), 0);
|
|
128
|
+
assertEq(nativeToken.balanceOf(endpoint), _fee);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { EndpointV2Mock } from "@layerzerolabs/test-devtools-evm-foundry/contracts/mocks/EndpointV2Mock.sol";
|
|
5
|
+
import { TestHelperOz5 } from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol";
|
|
6
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
7
|
+
import { OAppCoreBaseUpgradeable } from "./../contracts/oapp/OAppCoreBaseUpgradeable.sol";
|
|
8
|
+
import { OAppCoreRBACUpgradeable } from "./../contracts/oapp/OAppCoreRBACUpgradeable.sol";
|
|
9
|
+
|
|
10
|
+
contract OAppCoreRBACHarness is OAppCoreRBACUpgradeable {
|
|
11
|
+
constructor(address _endpoint) OAppCoreBaseUpgradeable(_endpoint) {}
|
|
12
|
+
|
|
13
|
+
function initialize(address _initialAdmin) public initializer {
|
|
14
|
+
__OAppCoreBase_init(_initialAdmin);
|
|
15
|
+
__AccessControl2Step_init(_initialAdmin);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function oAppVersion() public pure returns (uint64 senderVersion, uint64 receiverVersion) {
|
|
19
|
+
return (1, 1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
contract OAppCoreRBACUpgradeableTest is TestHelperOz5 {
|
|
24
|
+
OAppCoreRBACHarness oapp;
|
|
25
|
+
EndpointV2Mock endpoint;
|
|
26
|
+
|
|
27
|
+
address owner;
|
|
28
|
+
address alice = makeAddr("alice");
|
|
29
|
+
address bob = makeAddr("bob");
|
|
30
|
+
address proxyAdmin;
|
|
31
|
+
|
|
32
|
+
function setUp() public override {
|
|
33
|
+
owner = address(this);
|
|
34
|
+
setUpEndpoints(2, LibraryType.SimpleMessageLib);
|
|
35
|
+
endpoint = endpointSetup.endpointList[0];
|
|
36
|
+
OAppCoreRBACHarness impl = new OAppCoreRBACHarness(address(endpoint));
|
|
37
|
+
|
|
38
|
+
uint256 currentNonce = vm.getNonce(address(this));
|
|
39
|
+
proxyAdmin = vm.computeCreateAddress(vm.computeCreateAddress(address(this), currentNonce), 1);
|
|
40
|
+
|
|
41
|
+
oapp = OAppCoreRBACHarness(
|
|
42
|
+
address(
|
|
43
|
+
new TransparentUpgradeableProxy(
|
|
44
|
+
address(impl),
|
|
45
|
+
address(this),
|
|
46
|
+
abi.encodeWithSelector(OAppCoreRBACHarness.initialize.selector, owner)
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ============ initialize ============
|
|
53
|
+
|
|
54
|
+
function test_initialize_SetsDelegate() public view {
|
|
55
|
+
assertEq(endpoint.delegates(address(oapp)), owner);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============ setDelegate ============
|
|
59
|
+
|
|
60
|
+
function test_setDelegate_Revert_CannotDirectlySetDelegate_Admin() public {
|
|
61
|
+
vm.expectRevert(OAppCoreRBACUpgradeable.CannotDirectlySetDelegate.selector);
|
|
62
|
+
oapp.setDelegate(alice);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function test_setDelegate_Revert_CannotDirectlySetDelegate_NonAdmin() public {
|
|
66
|
+
vm.expectRevert(OAppCoreRBACUpgradeable.CannotDirectlySetDelegate.selector);
|
|
67
|
+
vm.prank(alice);
|
|
68
|
+
oapp.setDelegate(alice);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ============ acceptDefaultAdminTransfer ============
|
|
72
|
+
|
|
73
|
+
function test_acceptDefaultAdminTransfer() public {
|
|
74
|
+
oapp.beginDefaultAdminTransfer(alice);
|
|
75
|
+
|
|
76
|
+
vm.prank(alice);
|
|
77
|
+
oapp.acceptDefaultAdminTransfer();
|
|
78
|
+
|
|
79
|
+
assertEq(endpoint.delegates(address(oapp)), alice);
|
|
80
|
+
assertTrue(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), alice));
|
|
81
|
+
assertFalse(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), owner));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function test_acceptDefaultAdminTransfer_ChainedTransfers() public {
|
|
85
|
+
oapp.beginDefaultAdminTransfer(alice);
|
|
86
|
+
vm.prank(alice);
|
|
87
|
+
oapp.acceptDefaultAdminTransfer();
|
|
88
|
+
|
|
89
|
+
assertEq(endpoint.delegates(address(oapp)), alice);
|
|
90
|
+
|
|
91
|
+
vm.prank(alice);
|
|
92
|
+
oapp.beginDefaultAdminTransfer(bob);
|
|
93
|
+
vm.prank(bob);
|
|
94
|
+
oapp.acceptDefaultAdminTransfer();
|
|
95
|
+
|
|
96
|
+
assertEq(endpoint.delegates(address(oapp)), bob);
|
|
97
|
+
assertTrue(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), bob));
|
|
98
|
+
assertFalse(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), alice));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function test_acceptDefaultAdminTransfer_Fuzz(address _newAdmin) public {
|
|
102
|
+
vm.assume(_newAdmin != address(0));
|
|
103
|
+
vm.assume(_newAdmin != proxyAdmin);
|
|
104
|
+
vm.assume(_newAdmin != owner);
|
|
105
|
+
|
|
106
|
+
oapp.beginDefaultAdminTransfer(_newAdmin);
|
|
107
|
+
|
|
108
|
+
vm.prank(_newAdmin);
|
|
109
|
+
oapp.acceptDefaultAdminTransfer();
|
|
110
|
+
|
|
111
|
+
assertEq(endpoint.delegates(address(oapp)), _newAdmin);
|
|
112
|
+
assertTrue(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), _newAdmin));
|
|
113
|
+
assertFalse(oapp.hasRole(oapp.DEFAULT_ADMIN_ROLE(), owner));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IOAppOptionsType3 } from "@layerzerolabs/oapp-evm-contracts/contracts/interfaces/IOAppOptionsType3.sol";
|
|
5
|
+
import { OptionsBuilder } from "@layerzerolabs/oapp-evm-contracts/contracts/oapp/libs/OptionsBuilder.sol";
|
|
6
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
7
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
8
|
+
import { Test } from "forge-std/Test.sol";
|
|
9
|
+
import { OAppOptionsType3BaseUpgradeable } from "./../contracts/oapp/options-type-3/OAppOptionsType3BaseUpgradeable.sol";
|
|
10
|
+
|
|
11
|
+
contract OAppOptionsType3BaseHarness is OAppOptionsType3BaseUpgradeable {
|
|
12
|
+
constructor() {
|
|
13
|
+
_disableInitializers();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function initialize() public initializer {
|
|
17
|
+
__OAppOptionsType3Base_init();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function setEnforcedOptions(IOAppOptionsType3.EnforcedOptionParam[] calldata _enforcedOptions) external {
|
|
21
|
+
_setEnforcedOptions(_enforcedOptions);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
contract OAppOptionsType3BaseUpgradeableTest is Test {
|
|
26
|
+
using OptionsBuilder for bytes;
|
|
27
|
+
|
|
28
|
+
IOAppOptionsType3 oapp;
|
|
29
|
+
|
|
30
|
+
uint16 internal constant SEND = 1;
|
|
31
|
+
uint16 internal constant SEND_AND_CALL = 2;
|
|
32
|
+
|
|
33
|
+
function _createOApp() internal virtual returns (IOAppOptionsType3) {
|
|
34
|
+
OAppOptionsType3BaseHarness impl = new OAppOptionsType3BaseHarness();
|
|
35
|
+
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
|
36
|
+
address(impl),
|
|
37
|
+
address(this),
|
|
38
|
+
abi.encodeWithSelector(OAppOptionsType3BaseHarness.initialize.selector)
|
|
39
|
+
);
|
|
40
|
+
return IOAppOptionsType3(address(proxy));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function setUp() public virtual {
|
|
44
|
+
oapp = _createOApp();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ============ initialize ============
|
|
48
|
+
|
|
49
|
+
function test_initialize_Revert_AlreadyInitialized() public virtual {
|
|
50
|
+
vm.expectRevert(Initializable.InvalidInitialization.selector);
|
|
51
|
+
OAppOptionsType3BaseHarness(address(oapp)).initialize();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ============ enforcedOptions ============
|
|
55
|
+
|
|
56
|
+
function test_enforcedOptions() public {
|
|
57
|
+
uint32 eid = 30101;
|
|
58
|
+
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
59
|
+
|
|
60
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
61
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, options);
|
|
62
|
+
oapp.setEnforcedOptions(params);
|
|
63
|
+
|
|
64
|
+
assertEq(oapp.enforcedOptions(eid, SEND), options);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function test_enforcedOptions_Empty() public view {
|
|
68
|
+
assertEq(oapp.enforcedOptions(1, SEND), bytes(""));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ============ setEnforcedOptions ============
|
|
72
|
+
|
|
73
|
+
function test_setEnforcedOptions() public {
|
|
74
|
+
uint32 eid = 30101;
|
|
75
|
+
bytes memory sendOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
76
|
+
bytes memory sendAndCallOptions = OptionsBuilder
|
|
77
|
+
.newOptions()
|
|
78
|
+
.addExecutorLzReceiveOption(200_000, 0)
|
|
79
|
+
.addExecutorLzComposeOption(0, 500_000, 0);
|
|
80
|
+
|
|
81
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](2);
|
|
82
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, sendOptions);
|
|
83
|
+
params[1] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND_AND_CALL, sendAndCallOptions);
|
|
84
|
+
|
|
85
|
+
vm.expectEmit(true, true, true, true, address(oapp));
|
|
86
|
+
emit IOAppOptionsType3.EnforcedOptionSet(params);
|
|
87
|
+
|
|
88
|
+
oapp.setEnforcedOptions(params);
|
|
89
|
+
|
|
90
|
+
assertEq(oapp.enforcedOptions(eid, SEND), sendOptions);
|
|
91
|
+
assertEq(oapp.enforcedOptions(eid, SEND_AND_CALL), sendAndCallOptions);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function test_setEnforcedOptions_EmptyOptionsResetsEnforced() public {
|
|
95
|
+
uint32 eid = 30101;
|
|
96
|
+
bytes memory sendOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
97
|
+
|
|
98
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
99
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, sendOptions);
|
|
100
|
+
oapp.setEnforcedOptions(params);
|
|
101
|
+
assertEq(oapp.enforcedOptions(eid, SEND), sendOptions);
|
|
102
|
+
|
|
103
|
+
// Reset enforced options with empty bytes.
|
|
104
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, bytes(""));
|
|
105
|
+
oapp.setEnforcedOptions(params);
|
|
106
|
+
assertEq(oapp.enforcedOptions(eid, SEND), bytes(""));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function test_setEnforcedOptions_Fuzz(uint32 _eid, uint16 _msgType, uint128 _gas) public {
|
|
110
|
+
_gas = uint128(bound(_gas, 1, type(uint128).max));
|
|
111
|
+
|
|
112
|
+
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(_gas, 0);
|
|
113
|
+
|
|
114
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
115
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(_eid, _msgType, options);
|
|
116
|
+
oapp.setEnforcedOptions(params);
|
|
117
|
+
|
|
118
|
+
assertEq(oapp.enforcedOptions(_eid, _msgType), options);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function test_setEnforcedOptions_Fuzz_Revert_InvalidOptionsType(uint16 _optionsType) public {
|
|
122
|
+
vm.assume(_optionsType != 3);
|
|
123
|
+
|
|
124
|
+
bytes memory options = abi.encodePacked(_optionsType);
|
|
125
|
+
|
|
126
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
127
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(1, SEND, options);
|
|
128
|
+
vm.expectRevert(abi.encodeWithSelector(IOAppOptionsType3.InvalidOptions.selector, options));
|
|
129
|
+
oapp.setEnforcedOptions(params);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ============ combineOptions ============
|
|
133
|
+
|
|
134
|
+
function test_combineOptions_CombinesType3Options() public {
|
|
135
|
+
uint32 eid = 30101;
|
|
136
|
+
bytes memory enforced = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
137
|
+
bytes32 receiver = bytes32(uint256(uint160(makeAddr("receiver"))));
|
|
138
|
+
|
|
139
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
140
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, enforced);
|
|
141
|
+
oapp.setEnforcedOptions(params);
|
|
142
|
+
|
|
143
|
+
bytes memory extraOptions = OptionsBuilder.newOptions().addExecutorNativeDropOption(1.2345 ether, receiver);
|
|
144
|
+
bytes memory expected = OptionsBuilder
|
|
145
|
+
.newOptions()
|
|
146
|
+
.addExecutorLzReceiveOption(200_000, 0)
|
|
147
|
+
.addExecutorNativeDropOption(1.2345 ether, receiver);
|
|
148
|
+
|
|
149
|
+
assertEq(oapp.combineOptions(eid, SEND, extraOptions), expected);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function test_combineOptions_NoExtraOptions() public {
|
|
153
|
+
uint32 eid = 30101;
|
|
154
|
+
bytes memory enforced = OptionsBuilder
|
|
155
|
+
.newOptions()
|
|
156
|
+
.addExecutorLzReceiveOption(200_000, 0)
|
|
157
|
+
.addExecutorLzComposeOption(0, 500_000, 0);
|
|
158
|
+
|
|
159
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
160
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND_AND_CALL, enforced);
|
|
161
|
+
oapp.setEnforcedOptions(params);
|
|
162
|
+
|
|
163
|
+
assertEq(oapp.combineOptions(eid, SEND_AND_CALL, bytes("")), enforced);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function test_combineOptions_NoEnforcedOptions() public view {
|
|
167
|
+
bytes memory callerOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(100_000, 0);
|
|
168
|
+
assertEq(oapp.combineOptions(1, SEND, callerOptions), callerOptions);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function test_combineOptions_PassthroughAfterReset() public {
|
|
172
|
+
uint32 eid = 30101;
|
|
173
|
+
bytes memory enforced = OptionsBuilder
|
|
174
|
+
.newOptions()
|
|
175
|
+
.addExecutorLzReceiveOption(200_000, 0)
|
|
176
|
+
.addExecutorLzComposeOption(0, 500_000, 0);
|
|
177
|
+
|
|
178
|
+
// Set enforced options.
|
|
179
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
180
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND_AND_CALL, enforced);
|
|
181
|
+
oapp.setEnforcedOptions(params);
|
|
182
|
+
|
|
183
|
+
// Reset enforced options with empty bytes.
|
|
184
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND_AND_CALL, bytes(""));
|
|
185
|
+
oapp.setEnforcedOptions(params);
|
|
186
|
+
|
|
187
|
+
// After reset, `combineOptions` should pass through caller options as-is.
|
|
188
|
+
bytes memory callerOptions = OptionsBuilder
|
|
189
|
+
.newOptions()
|
|
190
|
+
.addExecutorLzReceiveOption(100_000, 0)
|
|
191
|
+
.addExecutorLzComposeOption(0, 300_000, 0);
|
|
192
|
+
assertEq(oapp.combineOptions(eid, SEND_AND_CALL, callerOptions), callerOptions);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function test_combineOptions_Revert_SingleByteExtraOptions() public {
|
|
196
|
+
uint32 eid = 30101;
|
|
197
|
+
bytes memory enforced = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
198
|
+
|
|
199
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
200
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(eid, SEND, enforced);
|
|
201
|
+
oapp.setEnforcedOptions(params);
|
|
202
|
+
|
|
203
|
+
vm.expectRevert(abi.encodeWithSelector(IOAppOptionsType3.InvalidOptions.selector, hex"03"));
|
|
204
|
+
oapp.combineOptions(eid, SEND, hex"03");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function test_combineOptions_Fuzz(uint32 _eid, uint16 _msgType, uint128 _enforcedGas, uint128 _extraGas) public {
|
|
208
|
+
_enforcedGas = uint128(bound(_enforcedGas, 1, type(uint128).max));
|
|
209
|
+
_extraGas = uint128(bound(_extraGas, 1, type(uint128).max));
|
|
210
|
+
|
|
211
|
+
bytes memory enforced = OptionsBuilder.newOptions().addExecutorLzReceiveOption(_enforcedGas, 0);
|
|
212
|
+
|
|
213
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
214
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(_eid, _msgType, enforced);
|
|
215
|
+
oapp.setEnforcedOptions(params);
|
|
216
|
+
|
|
217
|
+
bytes memory extra = OptionsBuilder.newOptions().addExecutorLzReceiveOption(_extraGas, 0);
|
|
218
|
+
bytes memory expected = OptionsBuilder
|
|
219
|
+
.newOptions()
|
|
220
|
+
.addExecutorLzReceiveOption(_enforcedGas, 0)
|
|
221
|
+
.addExecutorLzReceiveOption(_extraGas, 0);
|
|
222
|
+
|
|
223
|
+
assertEq(oapp.combineOptions(_eid, _msgType, extra), expected);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function test_combineOptions_Fuzz_Revert_InvalidExtraOptionsType(uint16 _optionsType) public {
|
|
227
|
+
vm.assume(_optionsType != 3);
|
|
228
|
+
|
|
229
|
+
bytes memory enforced = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
230
|
+
|
|
231
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
232
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(1, SEND, enforced);
|
|
233
|
+
oapp.setEnforcedOptions(params);
|
|
234
|
+
|
|
235
|
+
bytes memory invalidOptions = abi.encodePacked(_optionsType);
|
|
236
|
+
vm.expectRevert(abi.encodeWithSelector(IOAppOptionsType3.InvalidOptions.selector, invalidOptions));
|
|
237
|
+
oapp.combineOptions(1, SEND, invalidOptions);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.22;
|
|
3
|
+
|
|
4
|
+
import { IOAppOptionsType3 } from "@layerzerolabs/oapp-evm-contracts/contracts/interfaces/IOAppOptionsType3.sol";
|
|
5
|
+
import { OptionsBuilder } from "@layerzerolabs/oapp-evm-contracts/contracts/oapp/libs/OptionsBuilder.sol";
|
|
6
|
+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
7
|
+
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
|
|
8
|
+
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
9
|
+
import { OAppOptionsType3RBACUpgradeable } from "./../contracts/oapp/options-type-3/OAppOptionsType3RBACUpgradeable.sol";
|
|
10
|
+
import { OAppOptionsType3BaseUpgradeableTest } from "./OAppOptionsType3BaseUpgradeable.t.sol";
|
|
11
|
+
|
|
12
|
+
contract OAppOptionsType3RBACHarness is OAppOptionsType3RBACUpgradeable {
|
|
13
|
+
constructor() {
|
|
14
|
+
_disableInitializers();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function initialize(address _initialAdmin) public initializer {
|
|
18
|
+
__AccessControl2Step_init(_initialAdmin);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
contract OAppOptionsType3RBACUpgradeableTest is OAppOptionsType3BaseUpgradeableTest {
|
|
23
|
+
using OptionsBuilder for bytes;
|
|
24
|
+
|
|
25
|
+
address alice = makeAddr("alice");
|
|
26
|
+
|
|
27
|
+
function _createOApp() internal virtual override returns (IOAppOptionsType3) {
|
|
28
|
+
OAppOptionsType3RBACHarness impl = new OAppOptionsType3RBACHarness();
|
|
29
|
+
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
|
30
|
+
address(impl),
|
|
31
|
+
address(this),
|
|
32
|
+
abi.encodeWithSelector(OAppOptionsType3RBACHarness.initialize.selector, address(this))
|
|
33
|
+
);
|
|
34
|
+
return IOAppOptionsType3(address(proxy));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function setUp() public override {
|
|
38
|
+
oapp = _createOApp();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ============ initialize ============
|
|
42
|
+
|
|
43
|
+
/// @dev Override since `OAppOptionsType3RBACHarness.initialize(address)` has a different signature.
|
|
44
|
+
function test_initialize_Revert_AlreadyInitialized() public override {
|
|
45
|
+
vm.expectRevert(Initializable.InvalidInitialization.selector);
|
|
46
|
+
OAppOptionsType3RBACHarness(address(oapp)).initialize(alice);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ============ setEnforcedOptions ============
|
|
50
|
+
|
|
51
|
+
function test_setEnforcedOptions_Revert_Unauthorized() public {
|
|
52
|
+
bytes memory sendOptions = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
|
|
53
|
+
|
|
54
|
+
IOAppOptionsType3.EnforcedOptionParam[] memory params = new IOAppOptionsType3.EnforcedOptionParam[](1);
|
|
55
|
+
params[0] = IOAppOptionsType3.EnforcedOptionParam(1, SEND, sendOptions);
|
|
56
|
+
|
|
57
|
+
vm.expectRevert(
|
|
58
|
+
abi.encodeWithSelector(
|
|
59
|
+
IAccessControl.AccessControlUnauthorizedAccount.selector,
|
|
60
|
+
alice,
|
|
61
|
+
OAppOptionsType3RBACHarness(address(oapp)).DEFAULT_ADMIN_ROLE()
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
vm.prank(alice);
|
|
65
|
+
oapp.setEnforcedOptions(params);
|
|
66
|
+
}
|
|
67
|
+
}
|