@layerzerolabs/protocol-v2-messagelib-evm-contracts 1.2.95

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 (88) hide show
  1. package/README.md +15 -0
  2. package/contracts/Executor.sol +339 -0
  3. package/contracts/ExecutorFeeLib.sol +241 -0
  4. package/contracts/MessageLibBase.sol +21 -0
  5. package/contracts/PriceFeed.sol +304 -0
  6. package/contracts/ReceiveLibBaseE2.sol +28 -0
  7. package/contracts/SendLibBase.sol +258 -0
  8. package/contracts/SendLibBaseE2.sol +140 -0
  9. package/contracts/SimpleReadExecutor.sol +110 -0
  10. package/contracts/Treasury.sol +74 -0
  11. package/contracts/Worker.sol +167 -0
  12. package/contracts/decompressor/DVNDecoder.sol +52 -0
  13. package/contracts/decompressor/DVNDecompressor.sol +70 -0
  14. package/contracts/decompressor/DecompressorExtension.sol +204 -0
  15. package/contracts/decompressor/ExecutorDecoder.sol +147 -0
  16. package/contracts/decompressor/ExecutorDecompressor.sol +58 -0
  17. package/contracts/interfaces/IExecutor.sol +47 -0
  18. package/contracts/interfaces/IExecutorFeeLib.sol +56 -0
  19. package/contracts/interfaces/ILayerZeroExecutor.sol +29 -0
  20. package/contracts/interfaces/ILayerZeroPriceFeed.sol +61 -0
  21. package/contracts/interfaces/ILayerZeroReadExecutor.sol +15 -0
  22. package/contracts/interfaces/ILayerZeroTreasury.sol +19 -0
  23. package/contracts/interfaces/IWorker.sol +29 -0
  24. package/contracts/libs/ExecutorOptions.sol +104 -0
  25. package/contracts/libs/SafeCall.sol +123 -0
  26. package/contracts/lowlat/EssenceDVNWrapper.sol +77 -0
  27. package/contracts/lowlat/MultiCall.sol +42 -0
  28. package/contracts/mocks/DVNMock.sol +28 -0
  29. package/contracts/mocks/ExecutorMock.sol +95 -0
  30. package/contracts/uln/LzExecutor.sol +129 -0
  31. package/contracts/uln/ReceiveUlnBase.sol +125 -0
  32. package/contracts/uln/SendUlnBase.sol +129 -0
  33. package/contracts/uln/UlnBase.sol +195 -0
  34. package/contracts/uln/dvn/DVN.sol +393 -0
  35. package/contracts/uln/dvn/DVNFeeLib.sol +288 -0
  36. package/contracts/uln/dvn/DeadDVN.sol +30 -0
  37. package/contracts/uln/dvn/MultiSig.sol +135 -0
  38. package/contracts/uln/dvn/SimpleReadDVN.sol +112 -0
  39. package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol +151 -0
  40. package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol +71 -0
  41. package/contracts/uln/dvn/adapters/DVNAdapterBase.sol +114 -0
  42. package/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL1.sol +126 -0
  43. package/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL2.sol +50 -0
  44. package/contracts/uln/dvn/adapters/avalanche/NOTES.md +4 -0
  45. package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol +152 -0
  46. package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol +127 -0
  47. package/contracts/uln/dvn/adapters/libs/DVNAdapterMessageCodec.sol +41 -0
  48. package/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL1.sol +86 -0
  49. package/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL2.sol +58 -0
  50. package/contracts/uln/interfaces/IDVN.sol +26 -0
  51. package/contracts/uln/interfaces/IDVNFeeLib.sol +56 -0
  52. package/contracts/uln/interfaces/ILayerZeroDVN.sol +34 -0
  53. package/contracts/uln/interfaces/ILayerZeroReadDVN.sol +27 -0
  54. package/contracts/uln/interfaces/IReceiveUlnE2.sol +13 -0
  55. package/contracts/uln/interfaces/adapters/IAxelarDVNAdapter.sol +50 -0
  56. package/contracts/uln/interfaces/adapters/IAxelarDVNAdapterFeeLib.sol +49 -0
  57. package/contracts/uln/interfaces/adapters/ICCIPDVNAdapter.sol +34 -0
  58. package/contracts/uln/interfaces/adapters/ICCIPDVNAdapterFeeLib.sol +46 -0
  59. package/contracts/uln/libs/DVNOptions.sol +181 -0
  60. package/contracts/uln/libs/ReadCmdCodecV1.sol +136 -0
  61. package/contracts/uln/libs/SupportedCmdTypes.sol +29 -0
  62. package/contracts/uln/libs/UlnOptions.sol +176 -0
  63. package/contracts/uln/readlib/ReadLib1002.sol +518 -0
  64. package/contracts/uln/readlib/ReadLib1002View.sol +98 -0
  65. package/contracts/uln/readlib/ReadLibBase.sol +187 -0
  66. package/contracts/uln/uln301/AddressSizeConfig.sol +22 -0
  67. package/contracts/uln/uln301/ReceiveLibBaseE1.sol +103 -0
  68. package/contracts/uln/uln301/ReceiveUln301.sol +83 -0
  69. package/contracts/uln/uln301/ReceiveUln301View.sol +89 -0
  70. package/contracts/uln/uln301/SendLibBaseE1.sol +194 -0
  71. package/contracts/uln/uln301/SendUln301.sol +99 -0
  72. package/contracts/uln/uln301/TreasuryFeeHandler.sol +41 -0
  73. package/contracts/uln/uln301/interfaces/IMessageLibE1.sol +22 -0
  74. package/contracts/uln/uln301/interfaces/INonceContract.sol +7 -0
  75. package/contracts/uln/uln301/interfaces/ITreasuryFeeHandler.sol +13 -0
  76. package/contracts/uln/uln301/interfaces/IUltraLightNode301.sol +7 -0
  77. package/contracts/uln/uln301/mocks/NonceContractMock.sol +23 -0
  78. package/contracts/uln/uln302/ReceiveUln302.sol +85 -0
  79. package/contracts/uln/uln302/ReceiveUln302View.sol +89 -0
  80. package/contracts/uln/uln302/SendUln302.sol +86 -0
  81. package/contracts/upgradeable/WorkerUpgradeable.sol +186 -0
  82. package/contracts/upgradeable/proxy/ProxyAdmin.sol +96 -0
  83. package/contracts/upgradeable/proxy/TransparentUpgradeableProxy.sol +131 -0
  84. package/dist/index.d.ts +7 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +6 -0
  87. package/dist/index.js.map +1 -0
  88. package/package.json +70 -0
@@ -0,0 +1,104 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
6
+
7
+ library ExecutorOptions {
8
+ using CalldataBytesLib for bytes;
9
+
10
+ uint8 internal constant WORKER_ID = 1;
11
+
12
+ uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
13
+ uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;
14
+ uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;
15
+ uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;
16
+ uint8 internal constant OPTION_TYPE_LZREAD = 5;
17
+
18
+ error Executor_InvalidLzReceiveOption();
19
+ error Executor_InvalidNativeDropOption();
20
+ error Executor_InvalidLzComposeOption();
21
+ error Executor_InvalidLzReadOption();
22
+
23
+ /// @dev decode the next executor option from the options starting from the specified cursor
24
+ /// @param _options [executor_id][executor_option][executor_id][executor_option]...
25
+ /// executor_option = [option_size][option_type][option]
26
+ /// option_size = len(option_type) + len(option)
27
+ /// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes
28
+ /// @param _cursor the cursor to start decoding from
29
+ /// @return optionType the type of the option
30
+ /// @return option the option of the executor
31
+ /// @return cursor the cursor to start decoding the next executor option
32
+ function nextExecutorOption(
33
+ bytes calldata _options,
34
+ uint256 _cursor
35
+ ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
36
+ unchecked {
37
+ // skip worker id
38
+ cursor = _cursor + 1;
39
+
40
+ // read option size
41
+ uint16 size = _options.toU16(cursor);
42
+ cursor += 2;
43
+
44
+ // read option type
45
+ optionType = _options.toU8(cursor);
46
+
47
+ // startCursor and endCursor are used to slice the option from _options
48
+ uint256 startCursor = cursor + 1; // skip option type
49
+ uint256 endCursor = cursor + size;
50
+ option = _options[startCursor:endCursor];
51
+ cursor += size;
52
+ }
53
+ }
54
+
55
+ function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {
56
+ if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();
57
+ gas = _option.toU128(0);
58
+ value = _option.length == 32 ? _option.toU128(16) : 0;
59
+ }
60
+
61
+ function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {
62
+ if (_option.length != 48) revert Executor_InvalidNativeDropOption();
63
+ amount = _option.toU128(0);
64
+ receiver = _option.toB32(16);
65
+ }
66
+
67
+ function decodeLzComposeOption(
68
+ bytes calldata _option
69
+ ) internal pure returns (uint16 index, uint128 gas, uint128 value) {
70
+ if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();
71
+ index = _option.toU16(0);
72
+ gas = _option.toU128(2);
73
+ value = _option.length == 34 ? _option.toU128(18) : 0;
74
+ }
75
+
76
+ function decodeLzReadOption(
77
+ bytes calldata _option
78
+ ) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {
79
+ if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();
80
+ gas = _option.toU128(0);
81
+ calldataSize = _option.toU32(16);
82
+ value = _option.length == 36 ? _option.toU128(20) : 0;
83
+ }
84
+
85
+ function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
86
+ return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);
87
+ }
88
+
89
+ function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {
90
+ return abi.encodePacked(_amount, _receiver);
91
+ }
92
+
93
+ function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
94
+ return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);
95
+ }
96
+
97
+ function encodeLzReadOption(
98
+ uint128 _gas,
99
+ uint32 _calldataSize,
100
+ uint128 _value
101
+ ) internal pure returns (bytes memory) {
102
+ return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);
103
+ }
104
+ }
@@ -0,0 +1,123 @@
1
+ // SPDX-License-Identifier: MIT OR Apache-2.0
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ /// @dev copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
6
+ library SafeCall {
7
+ /// @notice calls a contract with a specified gas limit and value and captures the return data
8
+ /// @param _target The address to call
9
+ /// @param _gas The amount of gas to forward to the remote contract
10
+ /// @param _value The value in wei to send to the remote contract
11
+ /// to memory.
12
+ /// @param _maxCopy The maximum number of bytes of returndata to copy
13
+ /// to memory.
14
+ /// @param _calldata The data to send to the remote contract
15
+ /// @return success and returndata, as `.call()`. Returndata is capped to
16
+ /// `_maxCopy` bytes.
17
+ function safeCall(
18
+ address _target,
19
+ uint256 _gas,
20
+ uint256 _value,
21
+ uint16 _maxCopy,
22
+ bytes memory _calldata
23
+ ) internal returns (bool, bytes memory) {
24
+ // check that target has code
25
+ uint size;
26
+ assembly {
27
+ size := extcodesize(_target)
28
+ }
29
+ if (size == 0) {
30
+ return (false, new bytes(0));
31
+ }
32
+
33
+ // set up for assembly call
34
+ uint256 _toCopy;
35
+ bool _success;
36
+ bytes memory _returnData = new bytes(_maxCopy);
37
+ // dispatch message to recipient
38
+ // by assembly calling "handle" function
39
+ // we call via assembly to avoid memcopying a very large returndata
40
+ // returned by a malicious contract
41
+ assembly {
42
+ _success := call(
43
+ _gas, // gas
44
+ _target, // recipient
45
+ _value, // ether value
46
+ add(_calldata, 0x20), // inloc
47
+ mload(_calldata), // inlen
48
+ 0, // outloc
49
+ 0 // outlen
50
+ )
51
+ // limit our copy to 100 bytes
52
+ _toCopy := returndatasize()
53
+ if gt(_toCopy, _maxCopy) {
54
+ _toCopy := _maxCopy
55
+ }
56
+ // Store the length of the copied bytes
57
+ mstore(_returnData, _toCopy)
58
+ // copy the bytes from returndata[0:_toCopy]
59
+ returndatacopy(add(_returnData, 0x20), 0, _toCopy)
60
+ }
61
+ return (_success, _returnData);
62
+ }
63
+
64
+ /// @notice Use when you _really_ really _really_ don't trust the called
65
+ /// contract. This prevents the called contract from causing reversion of
66
+ /// the caller in as many ways as we can.
67
+ /// @dev The main difference between this and a solidity low-level call is
68
+ /// that we limit the number of bytes that the callee can cause to be
69
+ /// copied to caller memory. This prevents stupid things like malicious
70
+ /// contracts returning 10,000,000 bytes causing a local OOG when copying
71
+ /// to memory.
72
+ /// @param _target The address to call
73
+ /// @param _gas The amount of gas to forward to the remote contract
74
+ /// @param _maxCopy The maximum number of bytes of returndata to copy
75
+ /// to memory.
76
+ /// @param _calldata The data to send to the remote contract
77
+ /// @return success and returndata, as `.call()`. Returndata is capped to
78
+ /// `_maxCopy` bytes.
79
+ function safeStaticCall(
80
+ address _target,
81
+ uint256 _gas,
82
+ uint16 _maxCopy,
83
+ bytes memory _calldata
84
+ ) internal view returns (bool, bytes memory) {
85
+ // check that target has code
86
+ uint size;
87
+ assembly {
88
+ size := extcodesize(_target)
89
+ }
90
+ if (size == 0) {
91
+ return (false, new bytes(0));
92
+ }
93
+
94
+ // set up for assembly call
95
+ uint256 _toCopy;
96
+ bool _success;
97
+ bytes memory _returnData = new bytes(_maxCopy);
98
+ // dispatch message to recipient
99
+ // by assembly calling "handle" function
100
+ // we call via assembly to avoid memcopying a very large returndata
101
+ // returned by a malicious contract
102
+ assembly {
103
+ _success := staticcall(
104
+ _gas, // gas
105
+ _target, // recipient
106
+ add(_calldata, 0x20), // inloc
107
+ mload(_calldata), // inlen
108
+ 0, // outloc
109
+ 0 // outlen
110
+ )
111
+ // limit our copy to 256 bytes
112
+ _toCopy := returndatasize()
113
+ if gt(_toCopy, _maxCopy) {
114
+ _toCopy := _maxCopy
115
+ }
116
+ // Store the length of the copied bytes
117
+ mstore(_returnData, _toCopy)
118
+ // copy the bytes from returndata[0:_toCopy]
119
+ returndatacopy(add(_returnData, 0x20), 0, _toCopy)
120
+ }
121
+ return (_success, _returnData);
122
+ }
123
+ }
@@ -0,0 +1,77 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
6
+
7
+ import { MultiCall } from "./MultiCall.sol";
8
+
9
+ /// @title EssenceDVNWrapper is a contract, used to execute multiple worker calls in a single transaction
10
+ /// The calls should be as follows:
11
+ /// 1. N calls to dvn.execute() to verify the payload on ULN
12
+ /// 2. 1 call to uln.commitVerification() to commit the verification into the endpoint
13
+ /// 3. 1 call to executor.execute() to execute lzReceive() on the endpoint
14
+ ///
15
+ /// Node: The DVN should assign EssenceDVNWrapper as an admin to the DVN contract.
16
+ ///
17
+ contract EssenceDVNWrapper is AccessControl, MultiCall {
18
+ bytes32 internal constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
19
+
20
+ error DVNWrapper_InvalidRole(bytes32 role);
21
+ error DVNWrapper_InvalidAdminCount();
22
+ error DVNWrapper_RoleRenouncingDisabled();
23
+
24
+ uint256 public adminCount;
25
+
26
+ modifier onlyAdmin(bytes32 _role) {
27
+ if (_role == ADMIN_ROLE) {
28
+ _checkRole(_role); // admin required
29
+ } else {
30
+ revert DVNWrapper_InvalidRole(_role);
31
+ }
32
+ _;
33
+ }
34
+
35
+ constructor(address[] memory admins) {
36
+ if (admins.length == 0) {
37
+ revert DVNWrapper_InvalidAdminCount();
38
+ }
39
+ for (uint i = 0; i < admins.length; i++) {
40
+ _setupRole(ADMIN_ROLE, admins[i]);
41
+ }
42
+ adminCount = admins.length;
43
+ }
44
+
45
+ function multiCall(
46
+ Call[] calldata _calls
47
+ ) public payable override onlyAdmin(ADMIN_ROLE) returns (bool[] memory successes, bytes[] memory results) {
48
+ (successes, results) = super.multiCall(_calls);
49
+ }
50
+
51
+ // ========================= Override Functions =========================
52
+
53
+ function grantRole(bytes32 _role, address _account) public override onlyAdmin(_role) {
54
+ _grantRole(_role, _account);
55
+ }
56
+
57
+ function revokeRole(bytes32 _role, address _account) public override onlyAdmin(_role) {
58
+ _revokeRole(_role, _account);
59
+ }
60
+
61
+ function renounceRole(bytes32 /*role*/, address /*account*/) public pure override {
62
+ revert DVNWrapper_RoleRenouncingDisabled();
63
+ }
64
+
65
+ function _grantRole(bytes32 _role, address _account) internal override {
66
+ if (_role == ADMIN_ROLE) ++adminCount;
67
+ super._grantRole(_role, _account);
68
+ }
69
+
70
+ function _revokeRole(bytes32 _role, address _account) internal override {
71
+ if (_role == ADMIN_ROLE) --adminCount;
72
+ if (adminCount == 0) {
73
+ revert DVNWrapper_InvalidAdminCount(); // not allowed to remove all admins
74
+ }
75
+ super._revokeRole(_role, _account);
76
+ }
77
+ }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
6
+
7
+ contract MultiCall {
8
+ struct Call {
9
+ address target;
10
+ bytes data;
11
+ uint256 gasLimit;
12
+ uint256 value;
13
+ bool revertOnError;
14
+ }
15
+
16
+ error NotEnoughGas(uint256 index, uint256 requested, uint256 available);
17
+ error CallReverted(uint256 index, bytes result);
18
+
19
+ function multiCall(
20
+ Call[] calldata _calls
21
+ ) public payable virtual returns (bool[] memory successes, bytes[] memory results) {
22
+ successes = new bool[](_calls.length);
23
+ results = new bytes[](_calls.length);
24
+
25
+ for (uint256 i = 0; i < _calls.length; i++) {
26
+ Call calldata call = _calls[i];
27
+
28
+ if (gasleft() < call.gasLimit) revert NotEnoughGas(i, call.gasLimit, gasleft());
29
+
30
+ (successes[i], results[i]) = call.target.call{
31
+ value: call.value,
32
+ gas: call.gasLimit == 0 ? gasleft() : call.gasLimit
33
+ }(call.data);
34
+
35
+ if (!successes[i] && _calls[i].revertOnError) revert CallReverted(i, results[i]);
36
+ }
37
+
38
+ if (address(this).balance > 0) {
39
+ Transfer.native(msg.sender, address(this).balance);
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+ pragma solidity 0.8.22;
3
+
4
+ import { ExecuteParam } from "../uln/dvn/DVN.sol";
5
+
6
+ contract DVNMock {
7
+ event Executed(uint32 vid, address target, bytes callData, uint256 expiration, bytes signatures);
8
+
9
+ uint32 public immutable vid;
10
+
11
+ constructor(uint32 _vid) {
12
+ vid = _vid;
13
+ }
14
+
15
+ function execute(ExecuteParam[] calldata _params) external {
16
+ for (uint256 i = 0; i < _params.length; i++) {
17
+ emit Executed(
18
+ _params[i].vid,
19
+ _params[i].target,
20
+ _params[i].callData,
21
+ _params[i].expiration,
22
+ _params[i].signatures
23
+ );
24
+ }
25
+ }
26
+
27
+ function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external {}
28
+ }
@@ -0,0 +1,95 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
6
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
7
+ import { IExecutor } from "../../contracts/interfaces/IExecutor.sol";
8
+
9
+ contract ExecutorMock {
10
+ using PacketV1Codec for bytes;
11
+
12
+ event NativeDropMeta(
13
+ uint32 srcEid,
14
+ bytes32 sender,
15
+ uint64 nonce,
16
+ uint32 dstEid,
17
+ address oapp,
18
+ uint256 nativeDropGasLimit
19
+ );
20
+ event NativeDropped(address receiver, uint256 amount);
21
+ event Executed301(bytes packet, uint256 gasLimit);
22
+ event Executed302(
23
+ uint32 srcEid,
24
+ bytes32 sender,
25
+ uint64 nonce,
26
+ address receiver,
27
+ bytes32 guid,
28
+ bytes message,
29
+ bytes extraData,
30
+ uint256 gasLimit
31
+ );
32
+
33
+ uint32 public immutable dstEid;
34
+
35
+ constructor(uint32 _dstEid) {
36
+ dstEid = _dstEid;
37
+ }
38
+
39
+ function nativeDrop(
40
+ Origin calldata _origin,
41
+ uint32 _dstEid,
42
+ address _oapp,
43
+ IExecutor.NativeDropParams[] calldata _nativeDropParams,
44
+ uint256 _nativeDropGasLimit
45
+ ) external payable {
46
+ _nativeDrop(_origin, _dstEid, _oapp, _nativeDropParams, _nativeDropGasLimit);
47
+ }
48
+
49
+ function nativeDropAndExecute301(
50
+ Origin calldata _origin,
51
+ IExecutor.NativeDropParams[] calldata _nativeDropParams,
52
+ uint256 _nativeDropGasLimit,
53
+ bytes calldata _packet,
54
+ uint256 _gasLimit
55
+ ) external payable {
56
+ _nativeDrop(_origin, _packet.dstEid(), _packet.receiverB20(), _nativeDropParams, _nativeDropGasLimit);
57
+ emit Executed301(_packet, _gasLimit);
58
+ }
59
+
60
+ function execute301(bytes calldata _packet, uint256 _gasLimit) external {
61
+ emit Executed301(_packet, _gasLimit);
62
+ }
63
+
64
+ function nativeDropAndExecute302(
65
+ IExecutor.NativeDropParams[] calldata _nativeDropParams,
66
+ uint256 _nativeDropGasLimit,
67
+ IExecutor.ExecutionParams calldata _executionParams
68
+ ) external payable {
69
+ _nativeDrop(_executionParams.origin, dstEid, _executionParams.receiver, _nativeDropParams, _nativeDropGasLimit);
70
+
71
+ emit Executed302(
72
+ _executionParams.origin.srcEid,
73
+ _executionParams.origin.sender,
74
+ _executionParams.origin.nonce,
75
+ _executionParams.receiver,
76
+ _executionParams.guid,
77
+ _executionParams.message,
78
+ _executionParams.extraData,
79
+ _executionParams.gasLimit
80
+ );
81
+ }
82
+
83
+ function _nativeDrop(
84
+ Origin calldata _origin,
85
+ uint32 _dstEid,
86
+ address _oapp,
87
+ IExecutor.NativeDropParams[] calldata _nativeDropParams,
88
+ uint256 _nativeDropGasLimit
89
+ ) internal {
90
+ for (uint256 i = 0; i < _nativeDropParams.length; i++) {
91
+ emit NativeDropped(_nativeDropParams[i].receiver, _nativeDropParams[i].amount);
92
+ }
93
+ emit NativeDropMeta(_origin.srcEid, _origin.sender, _origin.nonce, _dstEid, _oapp, _nativeDropGasLimit);
94
+ }
95
+ }
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
6
+ import { Proxied } from "hardhat-deploy/solc_0.8/proxy/Proxied.sol";
7
+
8
+ import { IReceiveUlnE2 } from "./interfaces/IReceiveUlnE2.sol";
9
+ import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
10
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
11
+
12
+ import { ExecutionState, EndpointV2ViewUpgradeable } from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2ViewUpgradeable.sol";
13
+
14
+ import { VerificationState } from "./uln302/ReceiveUln302View.sol";
15
+
16
+ struct LzReceiveParam {
17
+ Origin origin;
18
+ address receiver;
19
+ bytes32 guid;
20
+ bytes message;
21
+ bytes extraData;
22
+ uint256 gas;
23
+ uint256 value;
24
+ }
25
+
26
+ struct NativeDropParam {
27
+ address _receiver;
28
+ uint256 _amount;
29
+ }
30
+
31
+ interface IReceiveUlnView {
32
+ function verifiable(bytes calldata _packetHeader, bytes32 _payloadHash) external view returns (VerificationState);
33
+ }
34
+
35
+ contract LzExecutor is OwnableUpgradeable, EndpointV2ViewUpgradeable, Proxied {
36
+ error LzExecutor_Executed();
37
+ error LzExecutor_Verifying();
38
+ error LzExecutor_ReceiveLibViewNotSet();
39
+
40
+ event NativeWithdrawn(address _to, uint256 _amount);
41
+ event ReceiveLibViewSet(address _receiveLib, address _receiveLibView);
42
+
43
+ address public receiveUln302;
44
+ uint32 public localEid;
45
+
46
+ mapping(address receiveLib => address receiveLibView) public receiveLibToView;
47
+
48
+ function initialize(
49
+ address _receiveUln302,
50
+ address _receiveUln302View,
51
+ address _endpoint
52
+ ) external proxied initializer {
53
+ __Ownable_init();
54
+ __EndpointV2View_init(_endpoint);
55
+
56
+ receiveUln302 = _receiveUln302;
57
+ localEid = endpoint.eid();
58
+ receiveLibToView[_receiveUln302] = _receiveUln302View;
59
+ }
60
+
61
+ // ============================ OnlyOwner ===================================
62
+
63
+ function withdrawNative(address _to, uint256 _amount) external onlyOwner {
64
+ Transfer.native(_to, _amount);
65
+ emit NativeWithdrawn(_to, _amount);
66
+ }
67
+
68
+ function setReceiveLibView(address _receiveLib, address _receiveLibView) external onlyOwner {
69
+ receiveLibToView[_receiveLib] = _receiveLibView;
70
+ emit ReceiveLibViewSet(_receiveLib, _receiveLibView);
71
+ }
72
+
73
+ // ============================ External ===================================
74
+
75
+ /// @notice process for commit and execute
76
+ /// 1. check if executable, revert if executed, execute if executable
77
+ /// 2. check if verifiable, revert if verifying, commit if verifiable
78
+ /// 3. native drop
79
+ /// 4. try execute, will revert if not executable
80
+ function commitAndExecute(
81
+ address _receiveLib,
82
+ LzReceiveParam calldata _lzReceiveParam,
83
+ NativeDropParam[] calldata _nativeDropParams
84
+ ) external payable {
85
+ /// 1. check if executable, revert if executed
86
+ ExecutionState executionState = executable(_lzReceiveParam.origin, _lzReceiveParam.receiver);
87
+ if (executionState == ExecutionState.Executed) revert LzExecutor_Executed();
88
+
89
+ /// 2. if not executable, check if verifiable, revert if verifying, commit if verifiable
90
+ if (executionState != ExecutionState.Executable) {
91
+ address receiveLib = receiveUln302 == address(0x0) ? _receiveLib : address(receiveUln302);
92
+ bytes memory packetHeader = abi.encodePacked(
93
+ uint8(1), // packet version 1
94
+ _lzReceiveParam.origin.nonce,
95
+ _lzReceiveParam.origin.srcEid,
96
+ _lzReceiveParam.origin.sender,
97
+ localEid,
98
+ bytes32(uint256(uint160(_lzReceiveParam.receiver)))
99
+ );
100
+ bytes32 payloadHash = keccak256(abi.encodePacked(_lzReceiveParam.guid, _lzReceiveParam.message));
101
+
102
+ address receiveLibView = receiveLibToView[receiveLib];
103
+ if (receiveLibView == address(0x0)) revert LzExecutor_ReceiveLibViewNotSet();
104
+
105
+ VerificationState verificationState = IReceiveUlnView(receiveLibView).verifiable(packetHeader, payloadHash);
106
+ if (verificationState == VerificationState.Verifiable) {
107
+ // verification required
108
+ IReceiveUlnE2(receiveLib).commitVerification(packetHeader, payloadHash);
109
+ } else if (verificationState == VerificationState.Verifying) {
110
+ revert LzExecutor_Verifying();
111
+ }
112
+ }
113
+
114
+ /// 3. native drop
115
+ for (uint256 i = 0; i < _nativeDropParams.length; i++) {
116
+ NativeDropParam calldata param = _nativeDropParams[i];
117
+ Transfer.native(param._receiver, param._amount);
118
+ }
119
+
120
+ /// 4. try execute, will revert if not executable
121
+ endpoint.lzReceive{ gas: _lzReceiveParam.gas, value: _lzReceiveParam.value }(
122
+ _lzReceiveParam.origin,
123
+ _lzReceiveParam.receiver,
124
+ _lzReceiveParam.guid,
125
+ _lzReceiveParam.message,
126
+ _lzReceiveParam.extraData
127
+ );
128
+ }
129
+ }