@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,194 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
6
+ import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
7
+ import { GUID } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/GUID.sol";
8
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
9
+
10
+ import { IMessageLibE1 } from "./interfaces/IMessageLibE1.sol";
11
+ import { ITreasuryFeeHandler } from "./interfaces/ITreasuryFeeHandler.sol";
12
+ import { INonceContract } from "./interfaces/INonceContract.sol";
13
+ import { SendLibBase, WorkerOptions, ExecutorConfig } from "../../SendLibBase.sol";
14
+ import { AddressSizeConfig } from "./AddressSizeConfig.sol";
15
+
16
+ /// @dev send-side message library base contract on endpoint v1.
17
+ /// design:
18
+ /// 1/ it enforces the path definition on V1 and interacts with the nonce contract
19
+ /// 2/ quote: first executor, then verifier (e.g. DVNs), then treasury
20
+ /// 3/ send: first executor, then verifier (e.g. DVNs), then treasury. the treasury pay much be DoS-proof
21
+ abstract contract SendLibBaseE1 is SendLibBase, AddressSizeConfig, IMessageLibE1 {
22
+ INonceContract public immutable nonceContract;
23
+ ITreasuryFeeHandler public immutable treasuryFeeHandler;
24
+
25
+ // config
26
+ address internal lzToken;
27
+
28
+ // this event should be identical to the one on Endpoint V2
29
+ event PacketSent(bytes encodedPayload, bytes options, uint256 nativeFee, uint256 lzTokenFee);
30
+ event NativeFeeWithdrawn(address user, address receiver, uint256 amount);
31
+ event LzTokenSet(address token);
32
+
33
+ constructor(
34
+ address _endpoint,
35
+ uint256 _treasuryGasLimit,
36
+ uint256 _treasuryNativeFeeCap,
37
+ address _nonceContract,
38
+ uint32 _localEid,
39
+ address _treasuryFeeHandler
40
+ ) SendLibBase(_endpoint, _localEid, _treasuryGasLimit, _treasuryNativeFeeCap) {
41
+ nonceContract = INonceContract(_nonceContract);
42
+ treasuryFeeHandler = ITreasuryFeeHandler(_treasuryFeeHandler);
43
+ }
44
+
45
+ // ======================= OnlyEndpoint =======================
46
+ /// @dev the abstract process for send() is:
47
+ /// 1/ pay workers, which includes the executor and the validation workers
48
+ /// 2/ pay treasury
49
+ /// 3/ in EndpointV1, here we handle the fees and refunds
50
+ function send(
51
+ address _sender,
52
+ uint64, // _nonce
53
+ uint16 _dstEid,
54
+ bytes calldata _path, // remoteAddress + localAddress
55
+ bytes calldata _message,
56
+ address payable _refundAddress,
57
+ address _lzTokenPaymentAddress,
58
+ bytes calldata _options
59
+ ) external payable onlyEndpoint {
60
+ (bytes memory encodedPacket, uint256 totalNativeFee) = _payWorkers(_sender, _dstEid, _path, _message, _options);
61
+
62
+ // quote treasury fee
63
+ uint32 dstEid = _dstEid; // stack too deep
64
+ address sender = _sender; // stack too deep
65
+ bool payInLzToken = _lzTokenPaymentAddress != address(0x0) && address(lzToken) != address(0x0);
66
+ (uint256 treasuryNativeFee, uint256 lzTokenFee) = _payTreasury(sender, dstEid, totalNativeFee, payInLzToken);
67
+ totalNativeFee += treasuryNativeFee;
68
+
69
+ // pay native fee
70
+ // assert the user has attached enough native token for this address
71
+ if (msg.value < totalNativeFee) revert LZ_MessageLib_InsufficientMsgValue();
72
+ // refund if they send too much
73
+ uint256 refundAmt = msg.value - totalNativeFee;
74
+ if (refundAmt > 0) {
75
+ Transfer.native(_refundAddress, refundAmt);
76
+ }
77
+
78
+ // pay lz token fee if needed
79
+ if (lzTokenFee > 0) {
80
+ // in v2, we let user pass a payInLzToken boolean but always charging the sender
81
+ // likewise in v1, if _lzTokenPaymentAddress is passed, it must be the sender
82
+ if (_lzTokenPaymentAddress != sender) revert LZ_MessageLib_LzTokenPaymentAddressMustBeSender();
83
+ _payLzTokenFee(sender, lzTokenFee);
84
+ }
85
+
86
+ emit PacketSent(encodedPacket, _options, totalNativeFee, lzTokenFee);
87
+ }
88
+
89
+ // ======================= OnlyOwner =======================
90
+ function setLzToken(address _lzToken) external onlyOwner {
91
+ lzToken = _lzToken;
92
+ emit LzTokenSet(_lzToken);
93
+ }
94
+
95
+ function setTreasury(address _treasury) external onlyOwner {
96
+ _setTreasury(_treasury);
97
+ }
98
+
99
+ // ======================= External =======================
100
+ function withdrawFee(address _to, uint256 _amount) external {
101
+ _debitFee(_amount);
102
+ Transfer.native(_to, _amount);
103
+ emit NativeFeeWithdrawn(msg.sender, _to, _amount);
104
+ }
105
+
106
+ // ======================= View =======================
107
+ function estimateFees(
108
+ uint16 _dstEid,
109
+ address _sender,
110
+ bytes calldata _message,
111
+ bool _payInLzToken,
112
+ bytes calldata _options
113
+ ) external view returns (uint256 nativeFee, uint256 lzTokenFee) {
114
+ return _quote(_sender, _dstEid, _message.length, _payInLzToken, _options);
115
+ }
116
+
117
+ // ======================= Internal =======================
118
+ /// @dev path = remoteAddress + localAddress.
119
+ function _assertPath(address _sender, bytes calldata _path, uint256 remoteAddressSize) internal pure {
120
+ if (_path.length != 20 + remoteAddressSize) revert LZ_MessageLib_InvalidPath();
121
+ address srcInPath = AddressCast.toAddress(_path[remoteAddressSize:]);
122
+ if (_sender != srcInPath) revert LZ_MessageLib_InvalidSender();
123
+ }
124
+
125
+ function _payLzTokenFee(address _sender, uint256 _lzTokenFee) internal {
126
+ treasuryFeeHandler.payFee(
127
+ lzToken,
128
+ _sender,
129
+ _lzTokenFee, // the supplied fee is always equal to the required fee
130
+ _lzTokenFee,
131
+ treasury
132
+ );
133
+ }
134
+
135
+ /// @dev outbound does three things
136
+ /// @dev 1) asserts path
137
+ /// @dev 2) increments the nonce
138
+ /// @dev 3) assemble packet
139
+ /// @return packet to be sent to workers
140
+ function _outbound(
141
+ address _sender,
142
+ uint16 _dstEid,
143
+ bytes calldata _path,
144
+ bytes calldata _message
145
+ ) internal returns (Packet memory packet) {
146
+ // assert toAddress size
147
+ uint256 remoteAddressSize = addressSizes[_dstEid];
148
+ if (remoteAddressSize == 0) revert LZ_MessageLib_InvalidPath();
149
+ _assertPath(_sender, _path, remoteAddressSize);
150
+
151
+ // increment nonce
152
+ uint64 nonce = nonceContract.increment(_dstEid, _sender, _path);
153
+
154
+ bytes32 receiver = AddressCast.toBytes32(_path[0:remoteAddressSize]);
155
+
156
+ bytes32 guid = GUID.generate(nonce, localEid, _sender, _dstEid, receiver);
157
+
158
+ // assemble packet
159
+ packet = Packet(nonce, localEid, _sender, _dstEid, receiver, guid, _message);
160
+ }
161
+
162
+ /// 1/ handle executor
163
+ /// 2/ handle other workers
164
+ function _payWorkers(
165
+ address _sender,
166
+ uint16 _dstEid,
167
+ bytes calldata _path,
168
+ bytes calldata _message,
169
+ bytes calldata _options
170
+ ) internal returns (bytes memory encodedPacket, uint256 totalNativeFee) {
171
+ Packet memory packet = _outbound(_sender, _dstEid, _path, _message);
172
+
173
+ // split workers options
174
+ (bytes memory executorOptions, WorkerOptions[] memory verificationOptions) = _splitOptions(_options);
175
+
176
+ // handle executor
177
+ ExecutorConfig memory config = getExecutorConfig(_sender, _dstEid);
178
+ uint256 msgSize = packet.message.length;
179
+ _assertMessageSize(msgSize, config.maxMessageSize);
180
+ totalNativeFee += _payExecutor(config.executor, packet.dstEid, packet.sender, msgSize, executorOptions);
181
+
182
+ // handle other workers
183
+ (uint256 verifierFee, bytes memory packetBytes) = _payVerifier(packet, verificationOptions);
184
+ totalNativeFee += verifierFee;
185
+
186
+ encodedPacket = packetBytes;
187
+ }
188
+
189
+ // ======================= Virtual =======================
190
+ function _payVerifier(
191
+ Packet memory _packet, // packet is assembled in memory for endpoint-v1. so the location can not be calldata
192
+ WorkerOptions[] memory _options
193
+ ) internal virtual returns (uint256 otherWorkerFees, bytes memory encodedPacket);
194
+ }
@@ -0,0 +1,99 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
6
+
7
+ import { ExecutorConfig, WorkerOptions } from "../../SendLibBase.sol";
8
+ import { SendLibBaseE1 } from "./SendLibBaseE1.sol";
9
+ import { SendUlnBase } from "../SendUlnBase.sol";
10
+ import { UlnConfig } from "../UlnBase.sol";
11
+
12
+ /// @dev ULN301 will be deployed on EndpointV1 and is for backward compatibility with ULN302 on EndpointV2. 301 can talk to both 301 and 302
13
+ /// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
14
+ /// @dev In this case, it combines the logic of SendUlnBase and SendLibBaseE1
15
+ contract SendUln301 is SendUlnBase, SendLibBaseE1 {
16
+ uint256 internal constant CONFIG_TYPE_EXECUTOR = 1;
17
+ uint256 internal constant CONFIG_TYPE_ULN = 2;
18
+
19
+ error LZ_ULN_InvalidConfigType(uint256 configType);
20
+
21
+ constructor(
22
+ address _endpoint,
23
+ uint256 _treasuryGasLimit,
24
+ uint256 _treasuryGasForFeeCap,
25
+ address _nonceContract,
26
+ uint32 _localEid,
27
+ address _treasuryFeeHandler
28
+ )
29
+ SendLibBaseE1(
30
+ _endpoint,
31
+ _treasuryGasLimit,
32
+ _treasuryGasForFeeCap,
33
+ _nonceContract,
34
+ _localEid,
35
+ _treasuryFeeHandler
36
+ )
37
+ {}
38
+
39
+ // ============================ OnlyEndpoint ===================================
40
+
41
+ function setConfig(
42
+ uint16 _eid,
43
+ address _oapp,
44
+ uint256 _configType,
45
+ bytes calldata _config
46
+ ) external override onlyEndpoint {
47
+ _assertSupportedEid(_eid);
48
+ if (_configType == CONFIG_TYPE_EXECUTOR) {
49
+ _setExecutorConfig(_eid, _oapp, abi.decode(_config, (ExecutorConfig)));
50
+ } else if (_configType == CONFIG_TYPE_ULN) {
51
+ _setUlnConfig(_eid, _oapp, abi.decode(_config, (UlnConfig)));
52
+ } else {
53
+ revert LZ_ULN_InvalidConfigType(_configType);
54
+ }
55
+ }
56
+
57
+ // ============================ View ===================================
58
+
59
+ function getConfig(uint16 _eid, address _oapp, uint256 _configType) external view override returns (bytes memory) {
60
+ if (_configType == CONFIG_TYPE_EXECUTOR) {
61
+ return abi.encode(getExecutorConfig(_oapp, _eid));
62
+ } else if (_configType == CONFIG_TYPE_ULN) {
63
+ return abi.encode(getUlnConfig(_oapp, _eid));
64
+ } else {
65
+ revert LZ_ULN_InvalidConfigType(_configType);
66
+ }
67
+ }
68
+
69
+ function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
70
+ return (3, 0, 1);
71
+ }
72
+
73
+ function isSupportedEid(uint32 _eid) external view returns (bool) {
74
+ return _isSupportedEid(_eid);
75
+ }
76
+
77
+ // ============================ Internal ===================================
78
+
79
+ function _quoteVerifier(
80
+ address _sender,
81
+ uint32 _dstEid,
82
+ WorkerOptions[] memory _options
83
+ ) internal view override returns (uint256) {
84
+ return _quoteDVNs(_sender, _dstEid, _options);
85
+ }
86
+
87
+ function _payVerifier(
88
+ Packet memory _packet,
89
+ WorkerOptions[] memory _options
90
+ ) internal virtual override returns (uint256 otherWorkerFees, bytes memory encodedPacket) {
91
+ (otherWorkerFees, encodedPacket) = _payDVNs(fees, _packet, _options);
92
+ }
93
+
94
+ function _splitOptions(
95
+ bytes calldata _options
96
+ ) internal pure override returns (bytes memory, WorkerOptions[] memory) {
97
+ return _splitUlnOptions(_options);
98
+ }
99
+ }
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
6
+ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+
8
+ import { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
9
+
10
+ import { ITreasuryFeeHandler } from "./interfaces/ITreasuryFeeHandler.sol";
11
+
12
+ contract TreasuryFeeHandler is ITreasuryFeeHandler {
13
+ using SafeERC20 for IERC20;
14
+
15
+ ILayerZeroEndpoint public immutable endpoint;
16
+
17
+ error LZ_TreasuryFeeHandler_OnlySendLibrary();
18
+ error LZ_TreasuryFeeHandler_OnlyOnSending();
19
+ error LZ_TreasuryFeeHandler_InvalidAmount(uint256 required, uint256 supplied);
20
+
21
+ constructor(address _endpoint) {
22
+ endpoint = ILayerZeroEndpoint(_endpoint);
23
+ }
24
+
25
+ // @dev payer of layerzero token must be sender
26
+ function payFee(
27
+ address _lzToken,
28
+ address _sender,
29
+ uint256 _required,
30
+ uint256 _supplied,
31
+ address _treasury
32
+ ) external {
33
+ // only sender's message library can call this function and only when sending a payload
34
+ if (endpoint.getSendLibraryAddress(_sender) != msg.sender) revert LZ_TreasuryFeeHandler_OnlySendLibrary();
35
+ if (!endpoint.isSendingPayload()) revert LZ_TreasuryFeeHandler_OnlyOnSending();
36
+ if (_required > _supplied) revert LZ_TreasuryFeeHandler_InvalidAmount(_required, _supplied);
37
+
38
+ // send lz token fee to the treasury directly
39
+ IERC20(_lzToken).safeTransferFrom(_sender, _treasury, _required);
40
+ }
41
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { ILayerZeroMessagingLibrary } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroMessagingLibrary.sol";
6
+
7
+ /// extends ILayerZeroMessagingLibrary instead of ILayerZeroMessagingLibraryV2 for reducing the contract size
8
+ interface IMessageLibE1 is ILayerZeroMessagingLibrary {
9
+ error LZ_MessageLib_InvalidPath();
10
+ error LZ_MessageLib_InvalidSender();
11
+ error LZ_MessageLib_InsufficientMsgValue();
12
+ error LZ_MessageLib_LzTokenPaymentAddressMustBeSender();
13
+
14
+ function setLzToken(address _lzToken) external;
15
+
16
+ function setTreasury(address _treasury) external;
17
+
18
+ function withdrawFee(address _to, uint256 _amount) external;
19
+
20
+ // message libs of same major version are compatible
21
+ function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion);
22
+ }
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface INonceContract {
6
+ function increment(uint16 _chainId, address _ua, bytes calldata _path) external returns (uint64);
7
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ITreasuryFeeHandler {
6
+ function payFee(
7
+ address _lzToken,
8
+ address _sender,
9
+ uint256 _required,
10
+ uint256 _supplied,
11
+ address _treasury
12
+ ) external;
13
+ }
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface IUltraLightNode301 {
6
+ function commitVerification(bytes calldata _packet, uint256 _gasLimit) external;
7
+ }
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.19;
4
+
5
+ import { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
6
+
7
+ contract NonceContractMock {
8
+ error OnlySendLibrary();
9
+
10
+ ILayerZeroEndpoint public immutable endpoint;
11
+ mapping(uint16 dstEid => mapping(bytes path => uint64 nonce)) public outboundNonce;
12
+
13
+ constructor(address _endpoint) {
14
+ endpoint = ILayerZeroEndpoint(_endpoint);
15
+ }
16
+
17
+ function increment(uint16 _chainId, address _ua, bytes calldata _path) external returns (uint64) {
18
+ if (msg.sender != endpoint.getSendLibraryAddress(_ua)) {
19
+ revert OnlySendLibrary();
20
+ }
21
+ return ++outboundNonce[_chainId][_path];
22
+ }
23
+ }
@@ -0,0 +1,85 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
6
+ import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";
7
+ import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
8
+
9
+ import { IReceiveUlnE2 } from "../interfaces/IReceiveUlnE2.sol";
10
+ import { ReceiveUlnBase } from "../ReceiveUlnBase.sol";
11
+ import { ReceiveLibBaseE2 } from "../../ReceiveLibBaseE2.sol";
12
+ import { UlnConfig } from "../UlnBase.sol";
13
+
14
+ /// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
15
+ /// @dev In this case, it combines the logic of ReceiveUlnBase and ReceiveLibBaseE2
16
+ contract ReceiveUln302 is IReceiveUlnE2, ReceiveUlnBase, ReceiveLibBaseE2 {
17
+ using PacketV1Codec for bytes;
18
+
19
+ /// @dev CONFIG_TYPE_ULN=2 here to align with SendUln302/ReceiveUln302/ReceiveUln301
20
+ uint32 internal constant CONFIG_TYPE_ULN = 2;
21
+
22
+ error LZ_ULN_InvalidConfigType(uint32 configType);
23
+
24
+ constructor(address _endpoint) ReceiveLibBaseE2(_endpoint) {}
25
+
26
+ function supportsInterface(bytes4 _interfaceId) public view override returns (bool) {
27
+ return _interfaceId == type(IReceiveUlnE2).interfaceId || super.supportsInterface(_interfaceId);
28
+ }
29
+
30
+ // ============================ OnlyEndpoint ===================================
31
+
32
+ // only the ULN config on the receive side
33
+ function setConfig(address _oapp, SetConfigParam[] calldata _params) external override onlyEndpoint {
34
+ for (uint256 i = 0; i < _params.length; i++) {
35
+ SetConfigParam calldata param = _params[i];
36
+ _assertSupportedEid(param.eid);
37
+ if (param.configType == CONFIG_TYPE_ULN) {
38
+ _setUlnConfig(param.eid, _oapp, abi.decode(param.config, (UlnConfig)));
39
+ } else {
40
+ revert LZ_ULN_InvalidConfigType(param.configType);
41
+ }
42
+ }
43
+ }
44
+
45
+ // ============================ External ===================================
46
+
47
+ /// @dev dont need to check endpoint verifiable here to save gas, as it will reverts if not verifiable.
48
+ function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external {
49
+ _assertHeader(_packetHeader, localEid);
50
+
51
+ // cache these values to save gas
52
+ address receiver = _packetHeader.receiverB20();
53
+ uint32 srcEid = _packetHeader.srcEid();
54
+
55
+ UlnConfig memory config = getUlnConfig(receiver, srcEid);
56
+ _verifyAndReclaimStorage(config, keccak256(_packetHeader), _payloadHash);
57
+
58
+ Origin memory origin = Origin(srcEid, _packetHeader.sender(), _packetHeader.nonce());
59
+ // endpoint will revert if nonce <= lazyInboundNonce
60
+ ILayerZeroEndpointV2(endpoint).verify(origin, receiver, _payloadHash);
61
+ }
62
+
63
+ /// @dev for dvn to verify the payload
64
+ function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external {
65
+ _verify(_packetHeader, _payloadHash, _confirmations);
66
+ }
67
+
68
+ // ============================ View ===================================
69
+
70
+ function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view override returns (bytes memory) {
71
+ if (_configType == CONFIG_TYPE_ULN) {
72
+ return abi.encode(getUlnConfig(_oapp, _eid));
73
+ } else {
74
+ revert LZ_ULN_InvalidConfigType(_configType);
75
+ }
76
+ }
77
+
78
+ function isSupportedEid(uint32 _eid) external view override returns (bool) {
79
+ return _isSupportedEid(_eid);
80
+ }
81
+
82
+ function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
83
+ return (3, 0, 2);
84
+ }
85
+ }
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Proxied } from "hardhat-deploy/solc_0.8/proxy/Proxied.sol";
6
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
7
+ import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
8
+ import { EndpointV2ViewUpgradeable } from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2ViewUpgradeable.sol";
9
+ import { UlnConfig } from "../UlnBase.sol";
10
+
11
+ enum VerificationState {
12
+ Verifying,
13
+ Verifiable,
14
+ Verified,
15
+ NotInitializable
16
+ }
17
+
18
+ interface IReceiveUln302 {
19
+ function assertHeader(bytes calldata _packetHeader, uint32 _localEid) external pure;
20
+
21
+ function verifiable(
22
+ UlnConfig memory _config,
23
+ bytes32 _headerHash,
24
+ bytes32 _payloadHash
25
+ ) external view returns (bool);
26
+
27
+ function getUlnConfig(address _oapp, uint32 _remoteEid) external view returns (UlnConfig memory rtnConfig);
28
+ }
29
+
30
+ contract ReceiveUln302View is EndpointV2ViewUpgradeable, Proxied {
31
+ using PacketV1Codec for bytes;
32
+
33
+ IReceiveUln302 public receiveUln302;
34
+ uint32 internal localEid;
35
+
36
+ function initialize(address _endpoint, address _receiveUln302) external proxied initializer {
37
+ __EndpointV2View_init(_endpoint);
38
+ receiveUln302 = IReceiveUln302(_receiveUln302);
39
+ localEid = endpoint.eid();
40
+ }
41
+
42
+ /// @dev a ULN verifiable requires it to be endpoint verifiable and committable
43
+ function verifiable(bytes calldata _packetHeader, bytes32 _payloadHash) external view returns (VerificationState) {
44
+ receiveUln302.assertHeader(_packetHeader, localEid);
45
+
46
+ address receiver = _packetHeader.receiverB20();
47
+
48
+ Origin memory origin = Origin(_packetHeader.srcEid(), _packetHeader.sender(), _packetHeader.nonce());
49
+
50
+ // check endpoint initializable
51
+ if (!initializable(origin, receiver)) {
52
+ return VerificationState.NotInitializable;
53
+ }
54
+
55
+ // check endpoint verifiable
56
+ if (!_endpointVerifiable(origin, receiver, _payloadHash)) {
57
+ return VerificationState.Verified;
58
+ }
59
+
60
+ // check uln verifiable
61
+ if (
62
+ receiveUln302.verifiable(
63
+ receiveUln302.getUlnConfig(receiver, origin.srcEid),
64
+ keccak256(_packetHeader),
65
+ _payloadHash
66
+ )
67
+ ) {
68
+ return VerificationState.Verifiable;
69
+ }
70
+ return VerificationState.Verifying;
71
+ }
72
+
73
+ /// @dev checks for endpoint verifiable and endpoint has payload hash
74
+ function _endpointVerifiable(
75
+ Origin memory origin,
76
+ address _receiver,
77
+ bytes32 _payloadHash
78
+ ) internal view returns (bool) {
79
+ // check endpoint verifiable
80
+ if (!verifiable(origin, _receiver, address(receiveUln302), _payloadHash)) return false;
81
+
82
+ // if endpoint.verifiable, also check if the payload hash matches
83
+ // endpoint allows re-verify, check if this payload has already been verified
84
+ if (endpoint.inboundPayloadHash(_receiver, origin.srcEid, origin.sender, origin.nonce) == _payloadHash)
85
+ return false;
86
+
87
+ return true;
88
+ }
89
+ }
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
6
+ import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";
7
+
8
+ import { ExecutorConfig } from "../../SendLibBase.sol";
9
+ import { SendLibBaseE2, WorkerOptions } from "../../SendLibBaseE2.sol";
10
+ import { UlnConfig } from "../UlnBase.sol";
11
+ import { SendUlnBase } from "../SendUlnBase.sol";
12
+
13
+ /// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
14
+ /// @dev In this case, it combines the logic of SendUlnBase and SendLibBaseE2
15
+ contract SendUln302 is SendUlnBase, SendLibBaseE2 {
16
+ uint32 internal constant CONFIG_TYPE_EXECUTOR = 1;
17
+ uint32 internal constant CONFIG_TYPE_ULN = 2;
18
+
19
+ error LZ_ULN_InvalidConfigType(uint32 configType);
20
+
21
+ constructor(
22
+ address _endpoint,
23
+ uint256 _treasuryGasLimit,
24
+ uint256 _treasuryGasForFeeCap
25
+ ) SendLibBaseE2(_endpoint, _treasuryGasLimit, _treasuryGasForFeeCap) {}
26
+
27
+ // ============================ OnlyEndpoint ===================================
28
+
29
+ // on the send side the user can config both the executor and the ULN
30
+ function setConfig(address _oapp, SetConfigParam[] calldata _params) external override onlyEndpoint {
31
+ for (uint256 i = 0; i < _params.length; i++) {
32
+ SetConfigParam calldata param = _params[i];
33
+ _assertSupportedEid(param.eid);
34
+ if (param.configType == CONFIG_TYPE_EXECUTOR) {
35
+ _setExecutorConfig(param.eid, _oapp, abi.decode(param.config, (ExecutorConfig)));
36
+ } else if (param.configType == CONFIG_TYPE_ULN) {
37
+ _setUlnConfig(param.eid, _oapp, abi.decode(param.config, (UlnConfig)));
38
+ } else {
39
+ revert LZ_ULN_InvalidConfigType(param.configType);
40
+ }
41
+ }
42
+ }
43
+
44
+ // ============================ View ===================================
45
+
46
+ function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view override returns (bytes memory) {
47
+ if (_configType == CONFIG_TYPE_EXECUTOR) {
48
+ return abi.encode(getExecutorConfig(_oapp, _eid));
49
+ } else if (_configType == CONFIG_TYPE_ULN) {
50
+ return abi.encode(getUlnConfig(_oapp, _eid));
51
+ } else {
52
+ revert LZ_ULN_InvalidConfigType(_configType);
53
+ }
54
+ }
55
+
56
+ function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
57
+ return (3, 0, 2);
58
+ }
59
+
60
+ function isSupportedEid(uint32 _eid) external view override returns (bool) {
61
+ return _isSupportedEid(_eid);
62
+ }
63
+
64
+ // ============================ Internal ===================================
65
+
66
+ function _quoteVerifier(
67
+ address _sender,
68
+ uint32 _dstEid,
69
+ WorkerOptions[] memory _options
70
+ ) internal view override returns (uint256) {
71
+ return _quoteDVNs(_sender, _dstEid, _options);
72
+ }
73
+
74
+ function _payVerifier(
75
+ Packet calldata _packet,
76
+ WorkerOptions[] memory _options
77
+ ) internal override returns (uint256 otherWorkerFees, bytes memory encodedPacket) {
78
+ (otherWorkerFees, encodedPacket) = _payDVNs(fees, _packet, _options);
79
+ }
80
+
81
+ function _splitOptions(
82
+ bytes calldata _options
83
+ ) internal pure override returns (bytes memory, WorkerOptions[] memory) {
84
+ return _splitUlnOptions(_options);
85
+ }
86
+ }