@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,98 @@
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
+
10
+ import { ReadLibConfig } from "./ReadLibBase.sol";
11
+ import { ReadLib1002 } from "./ReadLib1002.sol";
12
+
13
+ enum VerificationState {
14
+ Verifying,
15
+ Verifiable,
16
+ Verified,
17
+ NotInitializable,
18
+ Reorged
19
+ }
20
+
21
+ contract ReadLib1002View is EndpointV2ViewUpgradeable, Proxied {
22
+ using PacketV1Codec for bytes;
23
+
24
+ ReadLib1002 public readLib;
25
+ uint32 internal localEid;
26
+
27
+ function initialize(address _endpoint, address payable _readLib) external proxied initializer {
28
+ __EndpointV2View_init(_endpoint);
29
+ readLib = ReadLib1002(_readLib);
30
+ localEid = endpoint.eid();
31
+ }
32
+
33
+ /// @dev get a verifiable payload hash based on the payloadHashLookup from the DVNs
34
+ function getVerifiablePayloadHash(
35
+ address _receiver,
36
+ uint32 _srcEid,
37
+ bytes32 _headerHash,
38
+ bytes32 _cmdHash
39
+ ) public view returns (bytes32) {
40
+ ReadLibConfig memory config = readLib.getReadLibConfig(_receiver, _srcEid);
41
+ uint8 dvnsLength = config.requiredDVNCount + config.optionalDVNCount;
42
+ for (uint8 i = 0; i < dvnsLength; ++i) {
43
+ address dvn = i < config.requiredDVNCount
44
+ ? config.requiredDVNs[i]
45
+ : config.optionalDVNs[i - config.requiredDVNCount];
46
+
47
+ bytes32 payloadHash = readLib.hashLookup(_headerHash, _cmdHash, dvn);
48
+ if (readLib.verifiable(config, _headerHash, _cmdHash, payloadHash)) {
49
+ return payloadHash;
50
+ }
51
+ }
52
+ return EMPTY_PAYLOAD_HASH; // not found
53
+ }
54
+
55
+ /// @dev a verifiable requires it to be endpoint verifiable and committable
56
+ function verifiable(bytes calldata _packetHeader, bytes32 _cmdHash) external view returns (VerificationState) {
57
+ address receiver = _packetHeader.receiverB20();
58
+ uint32 srcEid = _packetHeader.srcEid();
59
+
60
+ Origin memory origin = Origin(srcEid, _packetHeader.sender(), _packetHeader.nonce());
61
+
62
+ // check endpoint initializable
63
+ if (!initializable(origin, receiver)) {
64
+ return VerificationState.NotInitializable;
65
+ }
66
+
67
+ // check endpoint verifiable. if false, that means it is executed and can not be verified
68
+ if (!endpoint.verifiable(origin, receiver)) {
69
+ return VerificationState.Verified;
70
+ }
71
+
72
+ // get the verifiable payload hash
73
+ bytes32 payloadHash = getVerifiablePayloadHash(receiver, srcEid, keccak256(_packetHeader), _cmdHash);
74
+
75
+ if (payloadHash == EMPTY_PAYLOAD_HASH) {
76
+ // if payload hash is not empty, it is verified
77
+ if (endpoint.inboundPayloadHash(receiver, srcEid, origin.sender, origin.nonce) != EMPTY_PAYLOAD_HASH) {
78
+ return VerificationState.Verified;
79
+ }
80
+
81
+ // otherwise, it is verifying
82
+ return VerificationState.Verifying;
83
+ }
84
+
85
+ // check if the cmdHash matches
86
+ if (readLib.cmdHashLookup(receiver, srcEid, origin.nonce) != _cmdHash) {
87
+ return VerificationState.Reorged;
88
+ }
89
+
90
+ // check if the payload hash matches
91
+ // endpoint allows re-verify, check if this payload has already been verified
92
+ if (endpoint.inboundPayloadHash(receiver, origin.srcEid, origin.sender, origin.nonce) == payloadHash) {
93
+ return VerificationState.Verified;
94
+ }
95
+
96
+ return VerificationState.Verifiable;
97
+ }
98
+ }
@@ -0,0 +1,187 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
6
+
7
+ struct ReadLibConfig {
8
+ address executor;
9
+ // we store the length of required DVNs and optional DVNs instead of using DVN.length directly to save gas
10
+ uint8 requiredDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
11
+ uint8 optionalDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default)
12
+ uint8 optionalDVNThreshold; // (0, optionalDVNCount]
13
+ address[] requiredDVNs; // no duplicates. sorted an an ascending order. allowed overlap with optionalDVNs
14
+ address[] optionalDVNs; // no duplicates. sorted an an ascending order. allowed overlap with requiredDVNs
15
+ }
16
+
17
+ struct SetDefaultReadLibConfigParam {
18
+ uint32 eid;
19
+ ReadLibConfig config;
20
+ }
21
+
22
+ /// @dev includes the utility functions for checking ReadLib states and logics
23
+ abstract contract ReadLibBase is Ownable {
24
+ address internal constant DEFAULT_CONFIG = address(0);
25
+ // reserved values for
26
+ uint8 internal constant DEFAULT = 0;
27
+ uint8 internal constant NIL_DVN_COUNT = type(uint8).max;
28
+ // 127 to prevent total number of DVNs (127 * 2) exceeding uint8.max (255)
29
+ // by limiting the total size, it would help constraint the design of DVNOptions
30
+ uint8 private constant MAX_COUNT = (type(uint8).max - 1) / 2;
31
+
32
+ mapping(address oapp => mapping(uint32 eid => ReadLibConfig config)) internal readLibConfigs;
33
+
34
+ error LZ_RL_Unsorted();
35
+ error LZ_RL_InvalidRequiredDVNCount();
36
+ error LZ_RL_InvalidOptionalDVNCount();
37
+ error LZ_RL_AtLeastOneDVN();
38
+ error LZ_RL_InvalidOptionalDVNThreshold();
39
+ error LZ_RL_UnsupportedEid(uint32 eid);
40
+ error LZ_RL_InvalidExecutor();
41
+
42
+ event DefaultReadLibConfigsSet(SetDefaultReadLibConfigParam[] params);
43
+ event ReadLibConfigSet(address oapp, uint32 eid, ReadLibConfig config);
44
+
45
+ // ============================ OnlyOwner ===================================
46
+
47
+ /// @dev about the DEFAULT ReadLib config
48
+ /// 1) its values are all LITERAL (e.g. 0 is 0). whereas in the oapp ReadLib config, 0 (default value) points to the default ReadLib config
49
+ /// this design enables the oapp to point to DEFAULT config without explicitly setting the config
50
+ /// 2) its configuration is more restrictive than the oapp ReadLib config that
51
+ /// a) it must not use NIL value, where NIL is used only by oapps to indicate the LITERAL 0
52
+ /// b) it must have at least one DVN and executor
53
+ function setDefaultReadLibConfigs(SetDefaultReadLibConfigParam[] calldata _params) external onlyOwner {
54
+ for (uint256 i = 0; i < _params.length; ++i) {
55
+ SetDefaultReadLibConfigParam calldata param = _params[i];
56
+
57
+ // 2.a must not use NIL
58
+ if (param.config.requiredDVNCount == NIL_DVN_COUNT) revert LZ_RL_InvalidRequiredDVNCount();
59
+ if (param.config.optionalDVNCount == NIL_DVN_COUNT) revert LZ_RL_InvalidOptionalDVNCount();
60
+
61
+ // 2.b must have at least one dvn and executor
62
+ _assertAtLeastOneDVN(param.config);
63
+ if (param.config.executor == address(0x0)) revert LZ_RL_InvalidExecutor();
64
+
65
+ _setConfig(DEFAULT_CONFIG, param.eid, param.config);
66
+ }
67
+ emit DefaultReadLibConfigsSet(_params);
68
+ }
69
+
70
+ // ============================ View ===================================
71
+ // @dev assuming most oapps use default, we get default as memory and custom as storage to save gas
72
+ function getReadLibConfig(address _oapp, uint32 _remoteEid) public view returns (ReadLibConfig memory rtnConfig) {
73
+ ReadLibConfig storage defaultConfig = readLibConfigs[DEFAULT_CONFIG][_remoteEid];
74
+ ReadLibConfig storage customConfig = readLibConfigs[_oapp][_remoteEid];
75
+
76
+ address executor = customConfig.executor;
77
+ rtnConfig.executor = executor != address(0x0) ? executor : defaultConfig.executor;
78
+
79
+ if (customConfig.requiredDVNCount == DEFAULT) {
80
+ if (defaultConfig.requiredDVNCount > 0) {
81
+ // copy only if count > 0. save gas
82
+ rtnConfig.requiredDVNs = defaultConfig.requiredDVNs;
83
+ rtnConfig.requiredDVNCount = defaultConfig.requiredDVNCount;
84
+ } // else, do nothing
85
+ } else {
86
+ if (customConfig.requiredDVNCount != NIL_DVN_COUNT) {
87
+ rtnConfig.requiredDVNs = customConfig.requiredDVNs;
88
+ rtnConfig.requiredDVNCount = customConfig.requiredDVNCount;
89
+ } // else, do nothing
90
+ }
91
+
92
+ if (customConfig.optionalDVNCount == DEFAULT) {
93
+ if (defaultConfig.optionalDVNCount > 0) {
94
+ // copy only if count > 0. save gas
95
+ rtnConfig.optionalDVNs = defaultConfig.optionalDVNs;
96
+ rtnConfig.optionalDVNCount = defaultConfig.optionalDVNCount;
97
+ rtnConfig.optionalDVNThreshold = defaultConfig.optionalDVNThreshold;
98
+ }
99
+ } else {
100
+ if (customConfig.optionalDVNCount != NIL_DVN_COUNT) {
101
+ rtnConfig.optionalDVNs = customConfig.optionalDVNs;
102
+ rtnConfig.optionalDVNCount = customConfig.optionalDVNCount;
103
+ rtnConfig.optionalDVNThreshold = customConfig.optionalDVNThreshold;
104
+ }
105
+ }
106
+
107
+ // the final value must have at least one dvn
108
+ // it is possible that some default config result into 0 dvns
109
+ _assertAtLeastOneDVN(rtnConfig);
110
+ }
111
+
112
+ /// @dev Get the readLib config without the default config for the given remoteEid.
113
+ function getAppReadLibConfig(address _oapp, uint32 _remoteEid) external view returns (ReadLibConfig memory) {
114
+ return readLibConfigs[_oapp][_remoteEid];
115
+ }
116
+
117
+ // ============================ Internal ===================================
118
+ function _setReadLibConfig(uint32 _remoteEid, address _oapp, ReadLibConfig memory _param) internal {
119
+ _setConfig(_oapp, _remoteEid, _param);
120
+
121
+ // get ReadLib config again as a catch all to ensure the config is valid
122
+ getReadLibConfig(_oapp, _remoteEid);
123
+ emit ReadLibConfigSet(_oapp, _remoteEid, _param);
124
+ }
125
+
126
+ /// @dev a supported Eid must have a valid default readLib config, which has at least one dvn
127
+ function _isSupportedEid(uint32 _remoteEid) internal view returns (bool) {
128
+ ReadLibConfig storage defaultConfig = readLibConfigs[DEFAULT_CONFIG][_remoteEid];
129
+ return defaultConfig.requiredDVNCount > 0 || defaultConfig.optionalDVNThreshold > 0;
130
+ }
131
+
132
+ function _assertSupportedEid(uint32 _remoteEid) internal view {
133
+ if (!_isSupportedEid(_remoteEid)) revert LZ_RL_UnsupportedEid(_remoteEid);
134
+ }
135
+
136
+ // ============================ Private ===================================
137
+
138
+ function _assertAtLeastOneDVN(ReadLibConfig memory _config) private pure {
139
+ if (_config.requiredDVNCount == 0 && _config.optionalDVNThreshold == 0) revert LZ_RL_AtLeastOneDVN();
140
+ }
141
+
142
+ /// @dev this private function is used in both setDefaultReadLibConfigs and setReadLibConfig
143
+ function _setConfig(address _oapp, uint32 _eid, ReadLibConfig memory _param) private {
144
+ // @dev required dvns
145
+ // if dvnCount == NONE, dvns list must be empty
146
+ // if dvnCount == DEFAULT, dvn list must be empty
147
+ // otherwise, dvnList.length == dvnCount and assert the list is valid
148
+ if (_param.requiredDVNCount == NIL_DVN_COUNT || _param.requiredDVNCount == DEFAULT) {
149
+ if (_param.requiredDVNs.length != 0) revert LZ_RL_InvalidRequiredDVNCount();
150
+ } else {
151
+ if (_param.requiredDVNs.length != _param.requiredDVNCount || _param.requiredDVNCount > MAX_COUNT)
152
+ revert LZ_RL_InvalidRequiredDVNCount();
153
+ _assertNoDuplicates(_param.requiredDVNs);
154
+ }
155
+
156
+ // @dev optional dvns
157
+ // if optionalDVNCount == NONE, optionalDVNs list must be empty and threshold must be 0
158
+ // if optionalDVNCount == DEFAULT, optionalDVNs list must be empty and threshold must be 0
159
+ // otherwise, optionalDVNs.length == optionalDVNCount, threshold > 0 && threshold <= optionalDVNCount and assert the list is valid
160
+
161
+ // example use case: an oapp uses the DEFAULT 'required' but
162
+ // a) use a custom 1/1 dvn (practically a required dvn), or
163
+ // b) use a custom 2/3 dvn
164
+ if (_param.optionalDVNCount == NIL_DVN_COUNT || _param.optionalDVNCount == DEFAULT) {
165
+ if (_param.optionalDVNs.length != 0) revert LZ_RL_InvalidOptionalDVNCount();
166
+ if (_param.optionalDVNThreshold != 0) revert LZ_RL_InvalidOptionalDVNThreshold();
167
+ } else {
168
+ if (_param.optionalDVNs.length != _param.optionalDVNCount || _param.optionalDVNCount > MAX_COUNT)
169
+ revert LZ_RL_InvalidOptionalDVNCount();
170
+ if (_param.optionalDVNThreshold == 0 || _param.optionalDVNThreshold > _param.optionalDVNCount)
171
+ revert LZ_RL_InvalidOptionalDVNThreshold();
172
+ _assertNoDuplicates(_param.optionalDVNs);
173
+ }
174
+ // don't assert valid count here, as it needs to be validated along side default config
175
+
176
+ readLibConfigs[_oapp][_eid] = _param;
177
+ }
178
+
179
+ function _assertNoDuplicates(address[] memory _dvns) private pure {
180
+ address lastDVN = address(0);
181
+ for (uint256 i = 0; i < _dvns.length; i++) {
182
+ address dvn = _dvns[i];
183
+ if (dvn <= lastDVN) revert LZ_RL_Unsorted(); // to ensure no duplicates
184
+ lastDVN = dvn;
185
+ }
186
+ }
187
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
6
+
7
+ abstract contract AddressSizeConfig is Ownable {
8
+ // EndpointV1 is using bytes as address. this map is for address length assertion
9
+ mapping(uint32 dstEid => uint256 size) public addressSizes;
10
+
11
+ event AddressSizeSet(uint16 eid, uint256 size);
12
+
13
+ error AddressSizeConfig_InvalidAddressSize();
14
+ error AddressSizeConfig_AddressSizeAlreadySet();
15
+
16
+ function setAddressSize(uint16 _eid, uint256 _size) external onlyOwner {
17
+ if (_size > 32) revert AddressSizeConfig_InvalidAddressSize();
18
+ if (addressSizes[_eid] != 0) revert AddressSizeConfig_AddressSizeAlreadySet();
19
+ addressSizes[_eid] = _size;
20
+ emit AddressSizeSet(_eid, _size);
21
+ }
22
+ }
@@ -0,0 +1,103 @@
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 { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
7
+ import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
8
+
9
+ import { AddressSizeConfig } from "./AddressSizeConfig.sol";
10
+ import { MessageLibBase } from "../../MessageLibBase.sol";
11
+
12
+ // only receiver function from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroMessagingLibrary.sol"
13
+ // because we are separating the send and receive libraries
14
+ interface ILayerZeroReceiveLibrary {
15
+ // setConfig / getConfig are User Application (UA) functions to specify Oracle, Relayer, blockConfirmations, libraryVersion
16
+ function setConfig(uint16 _chainId, address _userApplication, uint256 _configType, bytes calldata _config) external;
17
+
18
+ function getConfig(
19
+ uint16 _chainId,
20
+ address _userApplication,
21
+ uint256 _configType
22
+ ) external view returns (bytes memory);
23
+ }
24
+
25
+ struct SetDefaultExecutorParam {
26
+ uint32 eid;
27
+ address executor;
28
+ }
29
+
30
+ /// @dev receive-side message library base contract on endpoint v1.
31
+ /// design:
32
+ /// 1/ it provides an internal execute function that calls the endpoint. It enforces the path definition on V1.
33
+ /// 2/ it provides interfaces to configure executors that is whitelisted to execute the msg to prevent grieving
34
+ abstract contract ReceiveLibBaseE1 is MessageLibBase, AddressSizeConfig, ILayerZeroReceiveLibrary {
35
+ using AddressCast for bytes32;
36
+
37
+ mapping(address oapp => mapping(uint32 eid => address executor)) public executors;
38
+ mapping(uint32 eid => address executor) public defaultExecutors;
39
+
40
+ // this event is the same as the PacketDelivered event on EndpointV2
41
+ event PacketDelivered(Origin origin, address receiver);
42
+ event InvalidDst(
43
+ uint16 indexed srcChainId,
44
+ bytes32 srcAddress,
45
+ address indexed dstAddress,
46
+ uint64 nonce,
47
+ bytes32 payloadHash
48
+ );
49
+ event DefaultExecutorsSet(SetDefaultExecutorParam[] params);
50
+ event ExecutorSet(address oapp, uint32 eid, address executor);
51
+
52
+ error LZ_MessageLib_InvalidExecutor();
53
+ error LZ_MessageLib_OnlyExecutor();
54
+
55
+ constructor(address _endpoint, uint32 _localEid) MessageLibBase(_endpoint, _localEid) {}
56
+
57
+ function setDefaultExecutors(SetDefaultExecutorParam[] calldata _params) external onlyOwner {
58
+ for (uint256 i = 0; i < _params.length; ++i) {
59
+ SetDefaultExecutorParam calldata param = _params[i];
60
+ if (param.executor == address(0x0)) revert LZ_MessageLib_InvalidExecutor();
61
+ defaultExecutors[param.eid] = param.executor;
62
+ }
63
+ emit DefaultExecutorsSet(_params);
64
+ }
65
+
66
+ function getExecutor(address _oapp, uint32 _remoteEid) public view returns (address) {
67
+ address executor = executors[_oapp][_remoteEid];
68
+ return executor != address(0x0) ? executor : defaultExecutors[_remoteEid];
69
+ }
70
+
71
+ function _setExecutor(uint32 _remoteEid, address _oapp, address _executor) internal {
72
+ executors[_oapp][_remoteEid] = _executor;
73
+ emit ExecutorSet(_oapp, _remoteEid, _executor);
74
+ }
75
+
76
+ /// @dev this function change pack the path as required for EndpointV1
77
+ function _execute(
78
+ uint16 _srcEid,
79
+ bytes32 _sender,
80
+ address _receiver,
81
+ uint64 _nonce,
82
+ bytes memory _message,
83
+ uint256 _gasLimit
84
+ ) internal {
85
+ // if the executor is malicious, it can make the msg as a storedPayload or fail in the nonBlockingApp
86
+ // which might result in unintended behaviour and risks, like grieving.
87
+ // to err on the safe side, we should assert the executor here.
88
+ if (msg.sender != getExecutor(_receiver, _srcEid)) revert LZ_MessageLib_OnlyExecutor();
89
+
90
+ if (_receiver.code.length == 0) {
91
+ /// on chains where EOA has no codes, it will early return and emit InvalidDst event
92
+ // on chains where all address have codes, this will be skipped
93
+ emit InvalidDst(_srcEid, _sender, _receiver, _nonce, keccak256(_message));
94
+ return;
95
+ }
96
+
97
+ bytes memory pathData = abi.encodePacked(_sender.toBytes(addressSizes[_srcEid]), _receiver);
98
+ ILayerZeroEndpoint(endpoint).receivePayload(_srcEid, pathData, _receiver, _nonce, _gasLimit, _message);
99
+
100
+ Origin memory origin = Origin(_srcEid, _sender, _nonce);
101
+ emit PacketDelivered(origin, _receiver);
102
+ }
103
+ }
@@ -0,0 +1,83 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
6
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
7
+
8
+ import { IUltraLightNode301 } from "./interfaces/IUltraLightNode301.sol";
9
+ import { ReceiveLibBaseE1 } from "./ReceiveLibBaseE1.sol";
10
+ import { ReceiveUlnBase } from "../ReceiveUlnBase.sol";
11
+ import { UlnConfig } from "../UlnBase.sol";
12
+
13
+ /// @dev ULN301 will be deployed on EndpointV1 and is for backward compatibility with ULN302 on EndpointV2. 301 can talk to both 301 and 302
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 ReceiveLibBaseE1
16
+ contract ReceiveUln301 is IUltraLightNode301, ReceiveUlnBase, ReceiveLibBaseE1 {
17
+ using PacketV1Codec for bytes;
18
+ using SafeCast for uint32; // for chain ID uint32 to uint16 conversion
19
+
20
+ uint256 internal constant CONFIG_TYPE_EXECUTOR = 1;
21
+ uint256 internal constant CONFIG_TYPE_ULN = 2;
22
+
23
+ error LZ_ULN_InvalidConfigType(uint256 configType);
24
+
25
+ constructor(address _endpoint, uint32 _localEid) ReceiveLibBaseE1(_endpoint, _localEid) {}
26
+
27
+ // ============================ OnlyEndpoint ===================================
28
+
29
+ function setConfig(
30
+ uint16 _eid,
31
+ address _oapp,
32
+ uint256 _configType,
33
+ bytes calldata _config
34
+ ) external override onlyEndpoint {
35
+ _assertSupportedEid(_eid);
36
+ if (_configType == CONFIG_TYPE_EXECUTOR) {
37
+ _setExecutor(_eid, _oapp, abi.decode(_config, (address)));
38
+ } else if (_configType == CONFIG_TYPE_ULN) {
39
+ _setUlnConfig(_eid, _oapp, abi.decode(_config, (UlnConfig)));
40
+ } else {
41
+ revert LZ_ULN_InvalidConfigType(_configType);
42
+ }
43
+ }
44
+
45
+ // ============================ External ===================================
46
+
47
+ /// @dev in 301, this is equivalent to execution as in Endpoint V2
48
+ /// @dev dont need to check endpoint verifiable here to save gas, as it will reverts if not verifiable.
49
+ function commitVerification(bytes calldata _packet, uint256 _gasLimit) external {
50
+ bytes calldata header = _packet.header();
51
+ _assertHeader(header, localEid);
52
+
53
+ // cache these values to save gas
54
+ address receiver = _packet.receiverB20();
55
+ uint16 srcEid = _packet.srcEid().toUint16();
56
+
57
+ UlnConfig memory config = getUlnConfig(receiver, srcEid);
58
+ _verifyAndReclaimStorage(config, keccak256(header), _packet.payloadHash());
59
+
60
+ // endpoint will revert if nonce != ++inboundNonce
61
+ _execute(srcEid, _packet.sender(), receiver, _packet.nonce(), _packet.message(), _gasLimit);
62
+ }
63
+
64
+ function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external {
65
+ _verify(_packetHeader, _payloadHash, _confirmations);
66
+ }
67
+
68
+ // ============================ View ===================================
69
+
70
+ function getConfig(uint16 _eid, address _oapp, uint256 _configType) external view override returns (bytes memory) {
71
+ if (_configType == CONFIG_TYPE_EXECUTOR) {
72
+ return abi.encode(getExecutor(_oapp, _eid));
73
+ } else if (_configType == CONFIG_TYPE_ULN) {
74
+ return abi.encode(getUlnConfig(_oapp, _eid));
75
+ } else {
76
+ revert LZ_ULN_InvalidConfigType(_configType);
77
+ }
78
+ }
79
+
80
+ function version() external pure returns (uint64 major, uint8 minor, uint8 endpointVersion) {
81
+ return (3, 0, 1);
82
+ }
83
+ }
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
6
+ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7
+ import { Proxied } from "hardhat-deploy/solc_0.8/proxy/Proxied.sol";
8
+
9
+ import { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
10
+ import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
11
+ import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
12
+ import { ExecutionState, EndpointV2View } from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2View.sol";
13
+
14
+ import { UlnConfig } from "../UlnBase.sol";
15
+
16
+ enum VerificationState {
17
+ Verifying,
18
+ Verifiable,
19
+ Verified
20
+ }
21
+
22
+ interface IReceiveUln301 {
23
+ function assertHeader(bytes calldata _packetHeader, uint32 _localEid) external pure;
24
+
25
+ function addressSizes(uint32 _dstEid) external view returns (uint256);
26
+
27
+ function endpoint() external view returns (address);
28
+
29
+ function verifiable(
30
+ UlnConfig memory _config,
31
+ bytes32 _headerHash,
32
+ bytes32 _payloadHash
33
+ ) external view returns (bool);
34
+
35
+ function getUlnConfig(address _oapp, uint32 _remoteEid) external view returns (UlnConfig memory rtnConfig);
36
+ }
37
+
38
+ contract ReceiveUln301View is Initializable, Proxied {
39
+ using PacketV1Codec for bytes;
40
+ using AddressCast for bytes32;
41
+ using SafeCast for uint32;
42
+
43
+ ILayerZeroEndpoint public endpoint;
44
+ IReceiveUln301 public receiveUln301;
45
+ uint32 internal localEid;
46
+
47
+ function initialize(address _endpoint, uint32 _localEid, address _receiveUln301) external proxied initializer {
48
+ receiveUln301 = IReceiveUln301(_receiveUln301);
49
+ endpoint = ILayerZeroEndpoint(_endpoint);
50
+ localEid = _localEid;
51
+ }
52
+
53
+ function executable(bytes calldata _packetHeader, bytes32 _payloadHash) public view returns (ExecutionState) {
54
+ receiveUln301.assertHeader(_packetHeader, localEid);
55
+
56
+ address receiver = _packetHeader.receiverB20();
57
+ uint16 srcEid = _packetHeader.srcEid().toUint16();
58
+ uint64 nonce = _packetHeader.nonce();
59
+
60
+ // executed if nonce less than or equal to inboundNonce
61
+ bytes memory path = abi.encodePacked(
62
+ _packetHeader.sender().toBytes(receiveUln301.addressSizes(srcEid)),
63
+ receiver
64
+ );
65
+ if (nonce <= endpoint.getInboundNonce(srcEid, path)) return ExecutionState.Executed;
66
+
67
+ // executable if not executed and _verified
68
+ if (
69
+ receiveUln301.verifiable(
70
+ receiveUln301.getUlnConfig(receiver, srcEid),
71
+ keccak256(_packetHeader),
72
+ _payloadHash
73
+ )
74
+ ) {
75
+ return ExecutionState.Executable;
76
+ }
77
+
78
+ return ExecutionState.NotExecutable;
79
+ }
80
+
81
+ /// @dev keeping the same interface as 302
82
+ /// @dev a verifiable message requires it to be ULN verifiable only, excluding the endpoint verifiable check
83
+ function verifiable(bytes calldata _packetHeader, bytes32 _payloadHash) external view returns (VerificationState) {
84
+ if (executable(_packetHeader, _payloadHash) == ExecutionState.NotExecutable) {
85
+ return VerificationState.Verifying;
86
+ }
87
+ return VerificationState.Verified;
88
+ }
89
+ }