@layerzerolabs/lz-evm-messagelib-v2 2.0.2

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 (106) hide show
  1. package/artifacts/contracts/Executor.sol/Executor.json +1156 -0
  2. package/artifacts/contracts/ExecutorFeeLib.sol/ExecutorFeeLib.json +336 -0
  3. package/artifacts/contracts/MessageLibBase.sol/MessageLibBase.json +16 -0
  4. package/artifacts/contracts/PriceFeed.sol/PriceFeed.json +650 -0
  5. package/artifacts/contracts/ReceiveLibBaseE2.sol/ReceiveLibBaseE2.json +154 -0
  6. package/artifacts/contracts/SendLibBase.sol/SendLibBase.json +381 -0
  7. package/artifacts/contracts/SendLibBaseE2.sol/SendLibBaseE2.json +819 -0
  8. package/artifacts/contracts/Treasury.sol/Treasury.json +309 -0
  9. package/artifacts/contracts/Worker.sol/Worker.json +579 -0
  10. package/artifacts/contracts/interfaces/IExecutor.sol/IExecutor.json +429 -0
  11. package/artifacts/contracts/interfaces/IExecutorFeeLib.sol/IExecutorFeeLib.json +210 -0
  12. package/artifacts/contracts/interfaces/ILayerZeroExecutor.sol/ILayerZeroExecutor.json +79 -0
  13. package/artifacts/contracts/interfaces/ILayerZeroPriceFeed.sol/ILayerZeroPriceFeed.json +222 -0
  14. package/artifacts/contracts/interfaces/ILayerZeroTreasury.sol/ILayerZeroTreasury.json +79 -0
  15. package/artifacts/contracts/interfaces/IWorker.sol/IWorker.json +221 -0
  16. package/artifacts/contracts/libs/SafeCall.sol/SafeCall.json +10 -0
  17. package/artifacts/contracts/uln/LzExecutor.sol/LzExecutor.json +256 -0
  18. package/artifacts/contracts/uln/ReceiveUlnBase.sol/ReceiveUlnBase.json +472 -0
  19. package/artifacts/contracts/uln/SendUlnBase.sol/SendUlnBase.json +412 -0
  20. package/artifacts/contracts/uln/UlnBase.sol/UlnBase.json +387 -0
  21. package/artifacts/contracts/uln/dvn/DVN.sol/DVN.json +1370 -0
  22. package/artifacts/contracts/uln/dvn/DVNFeeLib.sol/DVNFeeLib.json +300 -0
  23. package/artifacts/contracts/uln/dvn/MultiSig.sol/MultiSig.json +164 -0
  24. package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol/CCIPDVNAdapter.json +742 -0
  25. package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol/CCIPDVNAdapterFeeLib.json +50 -0
  26. package/artifacts/contracts/uln/dvn/adapters/DVNAdapterBase.sol/DVNAdapterBase.json +463 -0
  27. package/artifacts/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol/DVNAdapterFeeLibBase.json +50 -0
  28. package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol/AxelarDVNAdapter.json +804 -0
  29. package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol/AxelarDVNAdapterFeeLib.json +50 -0
  30. package/artifacts/contracts/uln/interfaces/IDVN.sol/IDVN.json +370 -0
  31. package/artifacts/contracts/uln/interfaces/IDVNAdapterFeeLib.sol/IDVNAdapterFeeLib.json +50 -0
  32. package/artifacts/contracts/uln/interfaces/IDVNFeeLib.sol/IDVNFeeLib.json +178 -0
  33. package/artifacts/contracts/uln/interfaces/ILayerZeroDVN.sol/ILayerZeroDVN.json +96 -0
  34. package/artifacts/contracts/uln/interfaces/IReceiveUlnE2.sol/IReceiveUlnE2.json +76 -0
  35. package/artifacts/contracts/uln/libs/DVNOptions.sol/DVNOptions.json +27 -0
  36. package/artifacts/contracts/uln/libs/UlnOptions.sol/UlnOptions.json +54 -0
  37. package/artifacts/contracts/uln/uln301/AddressSizeConfig.sol/AddressSizeConfig.json +129 -0
  38. package/artifacts/contracts/uln/uln301/ReceiveLibBaseE1.sol/ILayerZeroReceiveLibrary.json +68 -0
  39. package/artifacts/contracts/uln/uln301/ReceiveLibBaseE1.sol/ReceiveLibBaseE1.json +416 -0
  40. package/artifacts/contracts/uln/uln301/ReceiveUln301.sol/ReceiveUln301.json +969 -0
  41. package/artifacts/contracts/uln/uln301/SendLibBaseE1.sol/SendLibBaseE1.json +804 -0
  42. package/artifacts/contracts/uln/uln301/SendUln301.sol/SendUln301.json +1278 -0
  43. package/artifacts/contracts/uln/uln301/TreasuryFeeHandler.sol/TreasuryFeeHandler.json +94 -0
  44. package/artifacts/contracts/uln/uln301/interfaces/IMessageLibE1.sol/IMessageLibE1.json +247 -0
  45. package/artifacts/contracts/uln/uln301/interfaces/INonceContract.sol/INonceContract.json +40 -0
  46. package/artifacts/contracts/uln/uln301/interfaces/ITreasuryFeeHandler.sol/ITreasuryFeeHandler.json +44 -0
  47. package/artifacts/contracts/uln/uln301/interfaces/IUltraLightNode301.sol/IUltraLightNode301.json +29 -0
  48. package/artifacts/contracts/uln/uln301/mocks/NonceContractMock.sol/NonceContractMock.json +93 -0
  49. package/artifacts/contracts/uln/uln302/ReceiveUln302.sol/ReceiveUln302.json +702 -0
  50. package/artifacts/contracts/uln/uln302/SendUln302.sol/SendUln302.json +1259 -0
  51. package/artifacts/contracts/upgradeable/WorkerUpgradeable.sol/WorkerUpgradeable.json +592 -0
  52. package/artifacts/contracts/upgradeable/proxy/ProxyAdmin.sol/ProxyAdmin.json +181 -0
  53. package/artifacts/contracts/upgradeable/proxy/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +160 -0
  54. package/contracts/Executor.sol +162 -0
  55. package/contracts/ExecutorFeeLib.sol +190 -0
  56. package/contracts/MessageLibBase.sol +21 -0
  57. package/contracts/PriceFeed.sol +257 -0
  58. package/contracts/ReceiveLibBaseE2.sol +54 -0
  59. package/contracts/SendLibBase.sol +258 -0
  60. package/contracts/SendLibBaseE2.sol +140 -0
  61. package/contracts/Treasury.sol +74 -0
  62. package/contracts/Worker.sol +167 -0
  63. package/contracts/interfaces/IExecutor.sol +44 -0
  64. package/contracts/interfaces/IExecutorFeeLib.sol +32 -0
  65. package/contracts/interfaces/ILayerZeroExecutor.sol +29 -0
  66. package/contracts/interfaces/ILayerZeroPriceFeed.sol +61 -0
  67. package/contracts/interfaces/ILayerZeroTreasury.sol +19 -0
  68. package/contracts/interfaces/IWorker.sol +29 -0
  69. package/contracts/libs/SafeCall.sol +123 -0
  70. package/contracts/uln/LzExecutor.sol +96 -0
  71. package/contracts/uln/ReceiveUlnBase.sol +118 -0
  72. package/contracts/uln/SendUlnBase.sol +129 -0
  73. package/contracts/uln/UlnBase.sol +195 -0
  74. package/contracts/uln/dvn/DVN.sol +349 -0
  75. package/contracts/uln/dvn/DVNFeeLib.sol +141 -0
  76. package/contracts/uln/dvn/MultiSig.sol +104 -0
  77. package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol +152 -0
  78. package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol +7 -0
  79. package/contracts/uln/dvn/adapters/DVNAdapterBase.sol +162 -0
  80. package/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol +20 -0
  81. package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol +156 -0
  82. package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol +7 -0
  83. package/contracts/uln/interfaces/IDVN.sol +25 -0
  84. package/contracts/uln/interfaces/IDVNAdapterFeeLib.sol +13 -0
  85. package/contracts/uln/interfaces/IDVNFeeLib.sol +30 -0
  86. package/contracts/uln/interfaces/ILayerZeroDVN.sol +34 -0
  87. package/contracts/uln/interfaces/IReceiveUlnE2.sol +18 -0
  88. package/contracts/uln/libs/DVNOptions.sol +181 -0
  89. package/contracts/uln/libs/UlnOptions.sol +176 -0
  90. package/contracts/uln/uln301/AddressSizeConfig.sol +22 -0
  91. package/contracts/uln/uln301/ReceiveLibBaseE1.sol +103 -0
  92. package/contracts/uln/uln301/ReceiveUln301.sol +120 -0
  93. package/contracts/uln/uln301/SendLibBaseE1.sol +194 -0
  94. package/contracts/uln/uln301/SendUln301.sol +99 -0
  95. package/contracts/uln/uln301/TreasuryFeeHandler.sol +41 -0
  96. package/contracts/uln/uln301/interfaces/IMessageLibE1.sol +22 -0
  97. package/contracts/uln/uln301/interfaces/INonceContract.sol +7 -0
  98. package/contracts/uln/uln301/interfaces/ITreasuryFeeHandler.sol +13 -0
  99. package/contracts/uln/uln301/interfaces/IUltraLightNode301.sol +7 -0
  100. package/contracts/uln/uln301/mocks/NonceContractMock.sol +23 -0
  101. package/contracts/uln/uln302/ReceiveUln302.sol +108 -0
  102. package/contracts/uln/uln302/SendUln302.sol +86 -0
  103. package/contracts/upgradeable/WorkerUpgradeable.sol +186 -0
  104. package/contracts/upgradeable/proxy/ProxyAdmin.sol +96 -0
  105. package/contracts/upgradeable/proxy/TransparentUpgradeableProxy.sol +131 -0
  106. package/package.json +51 -0
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { IExecutor } from "./IExecutor.sol";
6
+
7
+ interface IExecutorFeeLib {
8
+ struct FeeParams {
9
+ address priceFeed;
10
+ uint32 dstEid;
11
+ address sender;
12
+ uint256 calldataSize;
13
+ uint16 defaultMultiplierBps;
14
+ }
15
+
16
+ error NoOptions();
17
+ error NativeAmountExceedsCap(uint256 amount, uint256 cap);
18
+ error UnsupportedOptionType(uint8 optionType);
19
+ error InvalidExecutorOptions(uint256 cursor);
20
+
21
+ function getFeeOnSend(
22
+ FeeParams calldata _params,
23
+ IExecutor.DstConfig calldata _dstConfig,
24
+ bytes calldata _options
25
+ ) external returns (uint256 fee);
26
+
27
+ function getFee(
28
+ FeeParams calldata _params,
29
+ IExecutor.DstConfig calldata _dstConfig,
30
+ bytes calldata _options
31
+ ) external view returns (uint256 fee);
32
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ILayerZeroExecutor {
6
+ // @notice query price and assign jobs at the same time
7
+ // @param _dstEid - the destination endpoint identifier
8
+ // @param _sender - the source sending contract address. executors may apply price discrimination to senders
9
+ // @param _calldataSize - dynamic data size of message + caller params
10
+ // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
11
+ function assignJob(
12
+ uint32 _dstEid,
13
+ address _sender,
14
+ uint256 _calldataSize,
15
+ bytes calldata _options
16
+ ) external returns (uint256 price);
17
+
18
+ // @notice query the executor price for relaying the payload and its proof to the destination chain
19
+ // @param _dstEid - the destination endpoint identifier
20
+ // @param _sender - the source sending contract address. executors may apply price discrimination to senders
21
+ // @param _calldataSize - dynamic data size of message + caller params
22
+ // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
23
+ function getFee(
24
+ uint32 _dstEid,
25
+ address _sender,
26
+ uint256 _calldataSize,
27
+ bytes calldata _options
28
+ ) external view returns (uint256 price);
29
+ }
@@ -0,0 +1,61 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ILayerZeroPriceFeed {
6
+ /**
7
+ * @dev
8
+ * priceRatio: (USD price of 1 unit of remote native token in unit of local native token) * PRICE_RATIO_DENOMINATOR
9
+ */
10
+
11
+ struct Price {
12
+ uint128 priceRatio; // float value * 10 ^ 20, decimal awared. for aptos to evm, the basis would be (10^18 / 10^8) * 10 ^20 = 10 ^ 30.
13
+ uint64 gasPriceInUnit; // for evm, it is in wei, for aptos, it is in octas.
14
+ uint32 gasPerByte;
15
+ }
16
+
17
+ struct UpdatePrice {
18
+ uint32 eid;
19
+ Price price;
20
+ }
21
+
22
+ /**
23
+ * @dev
24
+ * ArbGasInfo.go:GetPricesInArbGas
25
+ *
26
+ */
27
+ struct ArbitrumPriceExt {
28
+ uint64 gasPerL2Tx; // L2 overhead
29
+ uint32 gasPerL1CallDataByte;
30
+ }
31
+
32
+ struct UpdatePriceExt {
33
+ uint32 eid;
34
+ Price price;
35
+ ArbitrumPriceExt extend;
36
+ }
37
+
38
+ error OnlyPriceUpdater();
39
+ error InsufficientFee(uint256 provided, uint256 required);
40
+ error UnknownL2Eid(uint32 l2Eid);
41
+
42
+ function nativeTokenPriceUSD() external view returns (uint128);
43
+
44
+ function getFee(uint32 _dstEid, uint256 _callDataSize, uint256 _gas) external view returns (uint256);
45
+
46
+ function getPrice(uint32 _dstEid) external view returns (Price memory);
47
+
48
+ function getPriceRatioDenominator() external view returns (uint128);
49
+
50
+ function estimateFeeByEid(
51
+ uint32 _dstEid,
52
+ uint256 _callDataSize,
53
+ uint256 _gas
54
+ ) external view returns (uint256 fee, uint128 priceRatio, uint128 priceRatioDenominator, uint128 nativePriceUSD);
55
+
56
+ function estimateFeeOnSend(
57
+ uint32 _dstEid,
58
+ uint256 _callDataSize,
59
+ uint256 _gas
60
+ ) external payable returns (uint256 fee, uint128 priceRatio, uint128 priceRatioDenominator, uint128 nativePriceUSD);
61
+ }
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ILayerZeroTreasury {
6
+ function getFee(
7
+ address _sender,
8
+ uint32 _dstEid,
9
+ uint256 _totalNativeFee,
10
+ bool _payInLzToken
11
+ ) external view returns (uint256 fee);
12
+
13
+ function payFee(
14
+ address _sender,
15
+ uint32 _dstEid,
16
+ uint256 _totalNativeFee,
17
+ bool _payInLzToken
18
+ ) external payable returns (uint256 fee);
19
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface IWorker {
6
+ event SetWorkerLib(address workerLib);
7
+ event SetPriceFeed(address priceFeed);
8
+ event SetDefaultMultiplierBps(uint16 multiplierBps);
9
+ event SetSupportedOptionTypes(uint32 dstEid, uint8[] optionTypes);
10
+ event Withdraw(address lib, address to, uint256 amount);
11
+
12
+ error NotAllowed();
13
+ error OnlyMessageLib();
14
+ error RoleRenouncingDisabled();
15
+
16
+ function setPriceFeed(address _priceFeed) external;
17
+
18
+ function priceFeed() external view returns (address);
19
+
20
+ function setDefaultMultiplierBps(uint16 _multiplierBps) external;
21
+
22
+ function defaultMultiplierBps() external view returns (uint16);
23
+
24
+ function withdrawFee(address _lib, address _to, uint256 _amount) external;
25
+
26
+ function setSupportedOptionTypes(uint32 _eid, uint8[] calldata _optionTypes) external;
27
+
28
+ function getSupportedOptionTypes(uint32 _eid) external view returns (uint8[] memory);
29
+ }
@@ -0,0 +1,123 @@
1
+ // SPDX-License-Identifier: MIT OR Apache-2.0
2
+
3
+ pragma solidity ^0.8.22;
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,96 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity 0.8.22;
4
+
5
+ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
6
+
7
+ import { IReceiveUlnE2 } from "./interfaces/IReceiveUlnE2.sol";
8
+ import { ILayerZeroEndpointV2, ExecutionState, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
9
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
10
+
11
+ import { VerificationState } from "./ReceiveUlnBase.sol";
12
+
13
+ struct LzReceiveParam {
14
+ Origin origin;
15
+ address receiver;
16
+ bytes32 guid;
17
+ bytes message;
18
+ bytes extraData;
19
+ uint256 gas;
20
+ uint256 value;
21
+ }
22
+
23
+ struct NativeDropParam {
24
+ address _receiver;
25
+ uint256 _amount;
26
+ }
27
+
28
+ contract LzExecutor is Ownable {
29
+ address public immutable receiveUln302;
30
+ ILayerZeroEndpointV2 public immutable endpoint;
31
+ uint32 public immutable localEid;
32
+
33
+ error Executed();
34
+ error Verifying();
35
+
36
+ constructor(address _receiveUln302, address _endpoint) {
37
+ receiveUln302 = _receiveUln302;
38
+ endpoint = ILayerZeroEndpointV2(_endpoint);
39
+ localEid = endpoint.eid();
40
+ }
41
+
42
+ /// @notice process for commit and execute
43
+ /// 1. check if executable, revert if executed, execute if executable
44
+ /// 2. check if verifiable, revert if verifying, commit if verifiable
45
+ /// 3. native drop
46
+ /// 4. try execute, will revert if not executable
47
+ function commitAndExecute(
48
+ address _receiveLib,
49
+ LzReceiveParam calldata _lzReceiveParam,
50
+ NativeDropParam calldata _nativeDropParam
51
+ ) external payable {
52
+ /// 1. check if executable, revert if executed
53
+ ExecutionState executionState = endpoint.executable(_lzReceiveParam.origin, _lzReceiveParam.receiver);
54
+ if (executionState == ExecutionState.Executed) revert Executed();
55
+
56
+ /// 2. if not executable, check if verifiable, revert if verifying, commit if verifiable
57
+ if (executionState != ExecutionState.Executable) {
58
+ address receiveLib = receiveUln302 == address(0x0) ? _receiveLib : address(receiveUln302);
59
+ bytes memory packetHeader = abi.encodePacked(
60
+ uint8(1), // packet version 1
61
+ _lzReceiveParam.origin.nonce,
62
+ _lzReceiveParam.origin.srcEid,
63
+ _lzReceiveParam.origin.sender,
64
+ localEid,
65
+ bytes32(uint256(uint160(_lzReceiveParam.receiver)))
66
+ );
67
+ bytes32 payloadHash = keccak256(abi.encodePacked(_lzReceiveParam.guid, _lzReceiveParam.message));
68
+
69
+ VerificationState verificationState = IReceiveUlnE2(receiveLib).verifiable(packetHeader, payloadHash);
70
+ if (verificationState == VerificationState.Verifiable) {
71
+ // verification required
72
+ IReceiveUlnE2(receiveLib).commitVerification(packetHeader, payloadHash);
73
+ } else if (verificationState == VerificationState.Verifying) {
74
+ revert Verifying();
75
+ }
76
+ }
77
+
78
+ /// 3. native drop
79
+ if (_nativeDropParam._amount > 0 && _nativeDropParam._receiver != address(0x0)) {
80
+ Transfer.native(_nativeDropParam._receiver, _nativeDropParam._amount);
81
+ }
82
+
83
+ /// 4. try execute, will revert if not executable
84
+ endpoint.lzReceive{ gas: _lzReceiveParam.gas, value: _lzReceiveParam.value }(
85
+ _lzReceiveParam.origin,
86
+ _lzReceiveParam.receiver,
87
+ _lzReceiveParam.guid,
88
+ _lzReceiveParam.message,
89
+ _lzReceiveParam.extraData
90
+ );
91
+ }
92
+
93
+ function withdrawNative(address _to, uint256 _amount) external onlyOwner {
94
+ Transfer.native(_to, _amount);
95
+ }
96
+ }
@@ -0,0 +1,118 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
6
+
7
+ import { UlnBase, UlnConfig } from "./UlnBase.sol";
8
+
9
+ enum VerificationState {
10
+ Verifying,
11
+ Verifiable,
12
+ Verified
13
+ }
14
+
15
+ struct Verification {
16
+ bool submitted;
17
+ uint64 confirmations;
18
+ }
19
+
20
+ /// @dev includes the utility functions for checking ULN states and logics
21
+ abstract contract ReceiveUlnBase is UlnBase {
22
+ using PacketV1Codec for bytes;
23
+
24
+ mapping(bytes32 headerHash => mapping(bytes32 payloadHash => mapping(address dvn => Verification)))
25
+ public hashLookup;
26
+
27
+ event PayloadVerified(address dvn, bytes header, uint256 confirmations, bytes32 proofHash);
28
+
29
+ error InvalidPacketHeader();
30
+ error InvalidPacketVersion();
31
+ error InvalidEid();
32
+ error Verifying();
33
+
34
+ // ============================ Internal ===================================
35
+ /// @dev per DVN signing function
36
+ function _verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) internal {
37
+ hashLookup[keccak256(_packetHeader)][_payloadHash][msg.sender] = Verification(true, _confirmations);
38
+ emit PayloadVerified(msg.sender, _packetHeader, _confirmations, _payloadHash);
39
+ }
40
+
41
+ function _verified(
42
+ address _dvn,
43
+ bytes32 _headerHash,
44
+ bytes32 _payloadHash,
45
+ uint64 _requiredConfirmation
46
+ ) internal view returns (bool verified) {
47
+ Verification memory verification = hashLookup[_headerHash][_payloadHash][_dvn];
48
+ // return true if the dvn has signed enough confirmations
49
+ verified = verification.submitted && verification.confirmations >= _requiredConfirmation;
50
+ }
51
+
52
+ function _verifyAndReclaimStorage(UlnConfig memory _config, bytes32 _headerHash, bytes32 _payloadHash) internal {
53
+ if (!_checkVerifiable(_config, _headerHash, _payloadHash)) {
54
+ revert Verifying();
55
+ }
56
+
57
+ // iterate the required DVNs
58
+ if (_config.requiredDVNCount > 0) {
59
+ for (uint8 i = 0; i < _config.requiredDVNCount; ++i) {
60
+ delete hashLookup[_headerHash][_payloadHash][_config.requiredDVNs[i]];
61
+ }
62
+ }
63
+
64
+ // iterate the optional DVNs
65
+ if (_config.optionalDVNCount > 0) {
66
+ for (uint8 i = 0; i < _config.optionalDVNCount; ++i) {
67
+ delete hashLookup[_headerHash][_payloadHash][_config.optionalDVNs[i]];
68
+ }
69
+ }
70
+ }
71
+
72
+ function _assertHeader(bytes calldata _packetHeader, uint32 _localEid) internal pure {
73
+ // assert packet header is of right size 81
74
+ if (_packetHeader.length != 81) revert InvalidPacketHeader();
75
+ // assert packet header version is the same as ULN
76
+ if (_packetHeader.version() != PacketV1Codec.PACKET_VERSION) revert InvalidPacketVersion();
77
+ // assert the packet is for this endpoint
78
+ if (_packetHeader.dstEid() != _localEid) revert InvalidEid();
79
+ }
80
+
81
+ /// @dev for verifiable view function
82
+ /// @dev checks if this verification is ready to be committed to the endpoint
83
+ function _checkVerifiable(
84
+ UlnConfig memory _config,
85
+ bytes32 _headerHash,
86
+ bytes32 _payloadHash
87
+ ) internal view returns (bool) {
88
+ // iterate the required DVNs
89
+ if (_config.requiredDVNCount > 0) {
90
+ for (uint8 i = 0; i < _config.requiredDVNCount; ++i) {
91
+ if (!_verified(_config.requiredDVNs[i], _headerHash, _payloadHash, _config.confirmations)) {
92
+ // return if any of the required DVNs haven't signed
93
+ return false;
94
+ }
95
+ }
96
+ if (_config.optionalDVNCount == 0) {
97
+ // returns early if all required DVNs have signed and there are no optional DVNs
98
+ return true;
99
+ }
100
+ }
101
+
102
+ // then it must require optional validations
103
+ uint8 threshold = _config.optionalDVNThreshold;
104
+ for (uint8 i = 0; i < _config.optionalDVNCount; ++i) {
105
+ if (_verified(_config.optionalDVNs[i], _headerHash, _payloadHash, _config.confirmations)) {
106
+ // increment the optional count if the optional DVN has signed
107
+ threshold--;
108
+ if (threshold == 0) {
109
+ // early return if the optional threshold has hit
110
+ return true;
111
+ }
112
+ }
113
+ }
114
+
115
+ // return false as a catch-all
116
+ return false;
117
+ }
118
+ }
@@ -0,0 +1,129 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
6
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
7
+
8
+ import { ILayerZeroDVN } from "./interfaces/ILayerZeroDVN.sol";
9
+ import { DVNOptions } from "./libs/DVNOptions.sol";
10
+ import { UlnOptions } from "./libs/UlnOptions.sol";
11
+ import { WorkerOptions } from "../SendLibBase.sol";
12
+ import { UlnConfig, UlnBase } from "./UlnBase.sol";
13
+
14
+ /// @dev includes the utility functions for checking ULN states and logics
15
+ abstract contract SendUlnBase is UlnBase {
16
+ event DVNFeePaid(address[] requiredDVNs, address[] optionalDVNs, uint256[] fees);
17
+
18
+ function _splitUlnOptions(bytes calldata _options) internal pure returns (bytes memory, WorkerOptions[] memory) {
19
+ (bytes memory executorOpts, bytes memory dvnOpts) = UlnOptions.decode(_options);
20
+
21
+ if (dvnOpts.length == 0) {
22
+ return (executorOpts, new WorkerOptions[](0));
23
+ }
24
+
25
+ WorkerOptions[] memory workerOpts = new WorkerOptions[](1);
26
+ workerOpts[0] = WorkerOptions(DVNOptions.WORKER_ID, dvnOpts);
27
+ return (executorOpts, workerOpts);
28
+ }
29
+
30
+ /// ---------- pay and assign jobs ----------
31
+
32
+ function _payDVNs(
33
+ mapping(address => uint256) storage _fees,
34
+ Packet memory _packet,
35
+ WorkerOptions[] memory _options
36
+ ) internal returns (uint256 totalFee, bytes memory encodedPacket) {
37
+ bytes memory packetHeader = PacketV1Codec.encodePacketHeader(_packet);
38
+ bytes memory payload = PacketV1Codec.encodePayload(_packet);
39
+ bytes32 payloadHash = keccak256(payload);
40
+ uint32 dstEid = _packet.dstEid;
41
+ address sender = _packet.sender;
42
+ UlnConfig memory config = getUlnConfig(sender, dstEid);
43
+
44
+ // if options is not empty, it must be dvn options
45
+ bytes memory dvnOptions = _options.length == 0 ? bytes("") : _options[0].options;
46
+ uint256[] memory dvnFees;
47
+ (totalFee, dvnFees) = _assignJobs(
48
+ _fees,
49
+ config,
50
+ ILayerZeroDVN.AssignJobParam(dstEid, packetHeader, payloadHash, config.confirmations, sender),
51
+ dvnOptions
52
+ );
53
+ encodedPacket = abi.encodePacked(packetHeader, payload);
54
+
55
+ emit DVNFeePaid(config.requiredDVNs, config.optionalDVNs, dvnFees);
56
+ }
57
+
58
+ function _assignJobs(
59
+ mapping(address => uint256) storage _fees,
60
+ UlnConfig memory _ulnConfig,
61
+ ILayerZeroDVN.AssignJobParam memory _param,
62
+ bytes memory dvnOptions
63
+ ) internal returns (uint256 totalFee, uint256[] memory dvnFees) {
64
+ (bytes[] memory optionsArray, uint8[] memory dvnIds) = DVNOptions.groupDVNOptionsByIdx(dvnOptions);
65
+
66
+ uint8 dvnsLength = _ulnConfig.requiredDVNCount + _ulnConfig.optionalDVNCount;
67
+ dvnFees = new uint256[](dvnsLength);
68
+ for (uint8 i = 0; i < dvnsLength; ++i) {
69
+ address dvn = i < _ulnConfig.requiredDVNCount
70
+ ? _ulnConfig.requiredDVNs[i]
71
+ : _ulnConfig.optionalDVNs[i - _ulnConfig.requiredDVNCount];
72
+
73
+ bytes memory options = "";
74
+ for (uint256 j = 0; j < dvnIds.length; ++j) {
75
+ if (dvnIds[j] == i) {
76
+ options = optionsArray[j];
77
+ break;
78
+ }
79
+ }
80
+
81
+ dvnFees[i] = ILayerZeroDVN(dvn).assignJob(_param, options);
82
+ if (dvnFees[i] > 0) {
83
+ _fees[dvn] += dvnFees[i];
84
+ totalFee += dvnFees[i];
85
+ }
86
+ }
87
+ }
88
+
89
+ /// ---------- quote ----------
90
+ function _quoteDVNs(
91
+ address _sender,
92
+ uint32 _dstEid,
93
+ WorkerOptions[] memory _options
94
+ ) internal view returns (uint256 totalFee) {
95
+ UlnConfig memory config = getUlnConfig(_sender, _dstEid);
96
+
97
+ // if options is not empty, it must be dvn options
98
+ bytes memory dvnOptions = _options.length == 0 ? bytes("") : _options[0].options;
99
+ (bytes[] memory optionsArray, uint8[] memory dvnIndices) = DVNOptions.groupDVNOptionsByIdx(dvnOptions);
100
+
101
+ totalFee = _getFees(config, _dstEid, _sender, optionsArray, dvnIndices);
102
+ }
103
+
104
+ function _getFees(
105
+ UlnConfig memory _config,
106
+ uint32 _dstEid,
107
+ address _sender,
108
+ bytes[] memory _optionsArray,
109
+ uint8[] memory _dvnIds
110
+ ) internal view returns (uint256 totalFee) {
111
+ // here we merge 2 list of dvns into 1 to allocate the indexed dvn options to the right dvn
112
+ uint8 dvnsLength = _config.requiredDVNCount + _config.optionalDVNCount;
113
+ for (uint8 i = 0; i < dvnsLength; ++i) {
114
+ address dvn = i < _config.requiredDVNCount
115
+ ? _config.requiredDVNs[i]
116
+ : _config.optionalDVNs[i - _config.requiredDVNCount];
117
+
118
+ bytes memory options = "";
119
+ // it is a double loop here. however, if the list is short, the cost is very acceptable.
120
+ for (uint256 j = 0; j < _dvnIds.length; ++j) {
121
+ if (_dvnIds[j] == i) {
122
+ options = _optionsArray[j];
123
+ break;
124
+ }
125
+ }
126
+ totalFee += ILayerZeroDVN(dvn).getFee(_dstEid, _config.confirmations, _sender, options);
127
+ }
128
+ }
129
+ }