@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,56 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { IDVN } from "./IDVN.sol";
6
+
7
+ interface IDVNFeeLib {
8
+ struct FeeParams {
9
+ address priceFeed;
10
+ uint32 dstEid;
11
+ uint64 confirmations;
12
+ address sender;
13
+ uint64 quorum;
14
+ uint16 defaultMultiplierBps;
15
+ }
16
+
17
+ struct FeeParamsForRead {
18
+ address priceFeed;
19
+ address sender;
20
+ uint64 quorum;
21
+ uint16 defaultMultiplierBps;
22
+ }
23
+
24
+ error DVN_UnsupportedOptionType(uint8 optionType);
25
+ error DVN_EidNotSupported(uint32 eid);
26
+ error DVN_TimestampOutOfRange(uint32 eid, uint64 timestamp);
27
+ error DVN_INVALID_INPUT_LENGTH();
28
+
29
+ function getFeeOnSend(
30
+ FeeParams calldata _params,
31
+ IDVN.DstConfig calldata _dstConfig,
32
+ bytes calldata _options
33
+ ) external payable returns (uint256 fee);
34
+
35
+ function getFee(
36
+ FeeParams calldata _params,
37
+ IDVN.DstConfig calldata _dstConfig,
38
+ bytes calldata _options
39
+ ) external view returns (uint256 fee);
40
+
41
+ function getFeeOnSend(
42
+ FeeParamsForRead calldata _params,
43
+ IDVN.DstConfig calldata _dstConfig,
44
+ bytes calldata _cmd,
45
+ bytes calldata _options
46
+ ) external payable returns (uint256 fee);
47
+
48
+ function getFee(
49
+ FeeParamsForRead calldata _params,
50
+ IDVN.DstConfig calldata _dstConfig,
51
+ bytes calldata _cmd,
52
+ bytes calldata _options
53
+ ) external view returns (uint256 fee);
54
+
55
+ function version() external view returns (uint64 major, uint8 minor);
56
+ }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ILayerZeroDVN {
6
+ struct AssignJobParam {
7
+ uint32 dstEid;
8
+ bytes packetHeader;
9
+ bytes32 payloadHash;
10
+ uint64 confirmations;
11
+ address sender;
12
+ }
13
+
14
+ // @notice query price and assign jobs at the same time
15
+ // @param _dstEid - the destination endpoint identifier
16
+ // @param _packetHeader - version + nonce + path
17
+ // @param _payloadHash - hash of guid + message
18
+ // @param _confirmations - block confirmation delay before relaying blocks
19
+ // @param _sender - the source sending contract address
20
+ // @param _options - options
21
+ function assignJob(AssignJobParam calldata _param, bytes calldata _options) external payable returns (uint256 fee);
22
+
23
+ // @notice query the dvn fee for relaying block information to the destination chain
24
+ // @param _dstEid the destination endpoint identifier
25
+ // @param _confirmations - block confirmation delay before relaying blocks
26
+ // @param _sender - the source sending contract address
27
+ // @param _options - options
28
+ function getFee(
29
+ uint32 _dstEid,
30
+ uint64 _confirmations,
31
+ address _sender,
32
+ bytes calldata _options
33
+ ) external view returns (uint256 fee);
34
+ }
@@ -0,0 +1,27 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ILayerZeroReadDVN {
6
+ // @notice query price and assign jobs at the same time
7
+ // @param _packetHeader - version + nonce + path
8
+ // @param _cmd - the command to be executed to obtain the payload
9
+ // @param _options - options
10
+ function assignJob(
11
+ address _sender,
12
+ bytes calldata _packetHeader,
13
+ bytes calldata _cmd,
14
+ bytes calldata _options
15
+ ) external payable returns (uint256 fee);
16
+
17
+ // @notice query the dvn fee for relaying block information to the destination chain
18
+ // @param _packetHeader - version + nonce + path
19
+ // @param _cmd - the command to be executed to obtain the payload
20
+ // @param _options - options
21
+ function getFee(
22
+ address _sender,
23
+ bytes calldata _packetHeader,
24
+ bytes calldata _cmd,
25
+ bytes calldata _options
26
+ ) external view returns (uint256 fee);
27
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ /// @dev should be implemented by the ReceiveUln302 contract and future ReceiveUln contracts on EndpointV2
6
+ interface IReceiveUlnE2 {
7
+ /// @notice for each dvn to verify the payload
8
+ /// @dev this function signature 0x0223536e
9
+ function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external;
10
+
11
+ /// @notice verify the payload at endpoint, will check if all DVNs verified
12
+ function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external;
13
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface IAxelarDVNAdapter {
6
+ struct MultiplierParam {
7
+ uint32 dstEid;
8
+ uint16 multiplierBps;
9
+ }
10
+
11
+ struct FloorMarginUSDParam {
12
+ uint32 dstEid;
13
+ uint128 floorMarginUSD;
14
+ }
15
+
16
+ struct NativeGasFeeParam {
17
+ uint32 dstEid;
18
+ uint256 nativeGasFee;
19
+ }
20
+
21
+ struct DstConfigParam {
22
+ uint32 eid;
23
+ string chainName;
24
+ string peer;
25
+ uint16 multiplierBps;
26
+ uint256 nativeGasFee;
27
+ }
28
+
29
+ struct DstConfig {
30
+ string chainName;
31
+ string peer;
32
+ uint16 multiplierBps;
33
+ uint256 nativeGasFee;
34
+ }
35
+
36
+ struct SrcConfig {
37
+ uint32 eid;
38
+ string peer;
39
+ }
40
+
41
+ event DstConfigSet(DstConfigParam[] params);
42
+ event NativeGasFeeSet(NativeGasFeeParam[] params);
43
+ event MultiplierSet(MultiplierParam[] params);
44
+ event FloorMarginUSDSet(FloorMarginUSDParam[] params);
45
+
46
+ error AxelarDVNAdapter_UntrustedPeer(string chainName, string peer);
47
+ error AxelarDVNAdapter_OnlyWorkerFeeLib();
48
+
49
+ function withdrawToFeeLib(address _sendLib) external;
50
+ }
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { IAxelarDVNAdapter } from "./IAxelarDVNAdapter.sol";
6
+
7
+ interface IAxelarDVNAdapterFeeLib {
8
+ struct Param {
9
+ uint32 dstEid;
10
+ uint64 confirmations;
11
+ address sender;
12
+ uint16 defaultMultiplierBps;
13
+ }
14
+
15
+ struct DstConfig {
16
+ uint64 gas;
17
+ uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
18
+ }
19
+
20
+ struct DstConfigParam {
21
+ uint32 dstEid;
22
+ uint64 gas;
23
+ uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
24
+ }
25
+
26
+ event DstConfigSet(DstConfigParam[] params);
27
+ event TokenWithdrawn(address token, address to, uint256 amount);
28
+ event GasServiceSet(address gasService);
29
+ event PriceFeedSet(address priceFeed);
30
+ event NativeGasFeeMultiplierBpsSet(uint16 multiplierBps);
31
+
32
+ error AxelarDVNAdapter_OptionsUnsupported();
33
+ error AxelarDVNAdapter_InsufficientBalance(uint256 actual, uint256 requested);
34
+ error AxelarDVNAdapter_EidNotSupported(uint32 eid);
35
+
36
+ function getFeeOnSend(
37
+ Param calldata _params,
38
+ IAxelarDVNAdapter.DstConfig calldata _dstConfig,
39
+ bytes memory _payload,
40
+ bytes calldata _options,
41
+ address _sendLib
42
+ ) external payable returns (uint256 totalFee);
43
+
44
+ function getFee(
45
+ Param calldata _params,
46
+ IAxelarDVNAdapter.DstConfig calldata _dstConfig,
47
+ bytes calldata _options
48
+ ) external view returns (uint256 totalFee);
49
+ }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ interface ICCIPDVNAdapter {
6
+ struct DstConfigParam {
7
+ uint32 eid;
8
+ uint16 multiplierBps;
9
+ uint64 chainSelector;
10
+ uint256 gas;
11
+ bytes peer;
12
+ }
13
+
14
+ struct DstConfig {
15
+ // https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet#ethereum-sepolia
16
+ // https://docs.chain.link/ccip/supported-networks/v1_0_0/mainnet
17
+ uint64 chainSelector;
18
+ uint16 multiplierBps;
19
+ // https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/ccip/libraries/Client.sol#L22C51-L22C51
20
+ // for destination is evm chain, need to use `abi.encode(address)` to get the peer
21
+ bytes peer;
22
+ uint256 gas;
23
+ }
24
+
25
+ struct SrcConfig {
26
+ uint32 eid;
27
+ bytes peer;
28
+ }
29
+
30
+ event DstConfigSet(DstConfigParam[] params);
31
+
32
+ error CCIPDVNAdapter_UntrustedPeer(uint64 chainSelector, bytes peer);
33
+ error CCIPDVNAdapter_InvalidRouter(address router);
34
+ }
@@ -0,0 +1,46 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { Client } from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
6
+ import { IRouterClient } from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
7
+ import { ICCIPDVNAdapter } from "./ICCIPDVNAdapter.sol";
8
+
9
+ interface ICCIPDVNAdapterFeeLib {
10
+ struct Param {
11
+ uint32 dstEid;
12
+ uint64 confirmations;
13
+ address sender;
14
+ uint16 defaultMultiplierBps;
15
+ }
16
+
17
+ struct DstConfig {
18
+ uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
19
+ }
20
+
21
+ struct DstConfigParam {
22
+ uint32 dstEid;
23
+ uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
24
+ }
25
+
26
+ event DstConfigSet(DstConfigParam[] params);
27
+
28
+ error CCIPDVNAdapter_OptionsUnsupported();
29
+ error CCIPDVNAdapter_EidNotSupported(uint32 eid);
30
+
31
+ function getFeeOnSend(
32
+ Param calldata _params,
33
+ ICCIPDVNAdapter.DstConfig calldata _dstConfig,
34
+ Client.EVM2AnyMessage calldata _message,
35
+ bytes calldata _options,
36
+ IRouterClient _router
37
+ ) external payable returns (uint256 ccipFee, uint256 totalFee);
38
+
39
+ function getFee(
40
+ Param calldata _params,
41
+ ICCIPDVNAdapter.DstConfig calldata _dstConfig,
42
+ Client.EVM2AnyMessage calldata _message,
43
+ bytes calldata _options,
44
+ IRouterClient _router
45
+ ) external view returns (uint256 totalFee);
46
+ }
@@ -0,0 +1,181 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
6
+
7
+ import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
8
+ import { CalldataBytesLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
9
+
10
+ library DVNOptions {
11
+ using CalldataBytesLib for bytes;
12
+ using BytesLib for bytes;
13
+
14
+ uint8 internal constant WORKER_ID = 2;
15
+ uint8 internal constant OPTION_TYPE_PRECRIME = 1;
16
+
17
+ error DVN_InvalidDVNIdx();
18
+ error DVN_InvalidDVNOptions(uint256 cursor);
19
+
20
+ /// @dev group dvn options by its idx
21
+ /// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...
22
+ /// dvn_option = [option_size][dvn_idx][option_type][option]
23
+ /// option_size = len(dvn_idx) + len(option_type) + len(option)
24
+ /// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes
25
+ /// @return dvnOptions the grouped options, still share the same format of _options
26
+ /// @return dvnIndices the dvn indices
27
+ function groupDVNOptionsByIdx(
28
+ bytes memory _options
29
+ ) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {
30
+ if (_options.length == 0) return (dvnOptions, dvnIndices);
31
+
32
+ uint8 numDVNs = getNumDVNs(_options);
33
+
34
+ // if there is only 1 dvn, we can just return the whole options
35
+ if (numDVNs == 1) {
36
+ dvnOptions = new bytes[](1);
37
+ dvnOptions[0] = _options;
38
+
39
+ dvnIndices = new uint8[](1);
40
+ dvnIndices[0] = _options.toUint8(3); // dvn idx
41
+ return (dvnOptions, dvnIndices);
42
+ }
43
+
44
+ // otherwise, we need to group the options by dvn_idx
45
+ dvnIndices = new uint8[](numDVNs);
46
+ dvnOptions = new bytes[](numDVNs);
47
+ unchecked {
48
+ uint256 cursor = 0;
49
+ uint256 start = 0;
50
+ uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx
51
+
52
+ while (cursor < _options.length) {
53
+ ++cursor; // skip worker_id
54
+
55
+ // optionLength asserted in getNumDVNs (skip check)
56
+ uint16 optionLength = _options.toUint16(cursor);
57
+ cursor += 2;
58
+
59
+ // dvnIdx asserted in getNumDVNs (skip check)
60
+ uint8 dvnIdx = _options.toUint8(cursor);
61
+
62
+ // dvnIdx must equal to the lastDVNIdx for the first option
63
+ // so it is always skipped in the first option
64
+ // this operation slices out options whenever the scan finds a different lastDVNIdx
65
+ if (lastDVNIdx == 255) {
66
+ lastDVNIdx = dvnIdx;
67
+ } else if (dvnIdx != lastDVNIdx) {
68
+ uint256 len = cursor - start - 3; // 3 is for worker_id and option_length
69
+ bytes memory opt = _options.slice(start, len);
70
+ _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);
71
+
72
+ // reset the start and lastDVNIdx
73
+ start += len;
74
+ lastDVNIdx = dvnIdx;
75
+ }
76
+
77
+ cursor += optionLength;
78
+ }
79
+
80
+ // skip check the cursor here because the cursor is asserted in getNumDVNs
81
+ // if we have reached the end of the options, we need to process the last dvn
82
+ uint256 size = cursor - start;
83
+ bytes memory op = _options.slice(start, size);
84
+ _insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);
85
+
86
+ // revert dvnIndices to start from 0
87
+ for (uint8 i = 0; i < numDVNs; ++i) {
88
+ --dvnIndices[i];
89
+ }
90
+ }
91
+ }
92
+
93
+ function _insertDVNOptions(
94
+ bytes[] memory _dvnOptions,
95
+ uint8[] memory _dvnIndices,
96
+ uint8 _dvnIdx,
97
+ bytes memory _newOptions
98
+ ) internal pure {
99
+ // dvnIdx starts from 0 but default value of dvnIndices is 0,
100
+ // so we tell if the slot is empty by adding 1 to dvnIdx
101
+ if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();
102
+ uint8 dvnIdxAdj = _dvnIdx + 1;
103
+
104
+ for (uint256 j = 0; j < _dvnIndices.length; ++j) {
105
+ uint8 index = _dvnIndices[j];
106
+ if (dvnIdxAdj == index) {
107
+ _dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);
108
+ break;
109
+ } else if (index == 0) {
110
+ // empty slot, that means it is the first time we see this dvn
111
+ _dvnIndices[j] = dvnIdxAdj;
112
+ _dvnOptions[j] = _newOptions;
113
+ break;
114
+ }
115
+ }
116
+ }
117
+
118
+ /// @dev get the number of unique dvns
119
+ /// @param _options the format is the same as groupDVNOptionsByIdx
120
+ function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {
121
+ uint256 cursor = 0;
122
+ BitMap256 bitmap;
123
+
124
+ // find number of unique dvn_idx
125
+ unchecked {
126
+ while (cursor < _options.length) {
127
+ ++cursor; // skip worker_id
128
+
129
+ uint16 optionLength = _options.toUint16(cursor);
130
+ cursor += 2;
131
+ if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type
132
+
133
+ uint8 dvnIdx = _options.toUint8(cursor);
134
+
135
+ // if dvnIdx is not set, increment numDVNs
136
+ // max num of dvns is 255, 255 is an invalid dvn_idx
137
+ // The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken
138
+ // the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has
139
+ // already enforced certain options can append additional options to the end of the enforced
140
+ // ones without restrictions.
141
+ if (dvnIdx == 255) revert DVN_InvalidDVNIdx();
142
+ if (!bitmap.get(dvnIdx)) {
143
+ ++numDVNs;
144
+ bitmap = bitmap.set(dvnIdx);
145
+ }
146
+
147
+ cursor += optionLength;
148
+ }
149
+ }
150
+ if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);
151
+ }
152
+
153
+ /// @dev decode the next dvn option from _options starting from the specified cursor
154
+ /// @param _options the format is the same as groupDVNOptionsByIdx
155
+ /// @param _cursor the cursor to start decoding
156
+ /// @return optionType the type of the option
157
+ /// @return option the option
158
+ /// @return cursor the cursor to start decoding the next option
159
+ function nextDVNOption(
160
+ bytes calldata _options,
161
+ uint256 _cursor
162
+ ) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
163
+ unchecked {
164
+ // skip worker id
165
+ cursor = _cursor + 1;
166
+
167
+ // read option size
168
+ uint16 size = _options.toU16(cursor);
169
+ cursor += 2;
170
+
171
+ // read option type
172
+ optionType = _options.toU8(cursor + 1); // skip dvn_idx
173
+
174
+ // startCursor and endCursor are used to slice the option from _options
175
+ uint256 startCursor = cursor + 2; // skip option type and dvn_idx
176
+ uint256 endCursor = cursor + size;
177
+ option = _options[startCursor:endCursor];
178
+ cursor += size;
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,136 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { SupportedCmdTypes, SupportedCmdTypesLib } from "./SupportedCmdTypes.sol";
6
+
7
+ library ReadCmdCodecV1 {
8
+ uint16 internal constant CMD_VERSION = 1;
9
+ uint8 internal constant REQUEST_VERSION = 1;
10
+ uint16 internal constant RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL = 1;
11
+ uint8 internal constant COMPUTE_VERSION = 1;
12
+ uint16 internal constant COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL = 1;
13
+
14
+ uint8 internal constant COMPUTE_SETTING_MAP_ONLY = 0;
15
+ uint8 internal constant COMPUTE_SETTING_REDUCE_ONLY = 1;
16
+ uint8 internal constant COMPUTE_SETTING_MAP_AND_REDUCE = 2;
17
+
18
+ error InvalidCmd();
19
+ error InvalidVersion();
20
+ error InvalidType();
21
+
22
+ struct Cmd {
23
+ uint16 numEvmCallRequestV1;
24
+ bool evmCallComputeV1Map;
25
+ bool evmCallComputeV1Reduce;
26
+ }
27
+
28
+ function decode(
29
+ bytes calldata _cmd,
30
+ function(uint32, bool, uint64, uint8) view _assertCmdTypeSupported
31
+ ) internal view returns (Cmd memory cmd) {
32
+ uint256 cursor = 0;
33
+ // decode the header in scope, depress stack too deep
34
+ {
35
+ uint16 cmdVersion = uint16(bytes2(_cmd[cursor:cursor + 2]));
36
+ cursor += 2;
37
+ if (cmdVersion != CMD_VERSION) revert InvalidVersion();
38
+
39
+ cursor += 2; // skip appCmdLabel
40
+
41
+ uint16 requestCount = uint16(bytes2(_cmd[cursor:cursor + 2]));
42
+ cursor += 2;
43
+
44
+ // there is only one request type in this version, so total request count should be the same as numEvmCallRequestV1
45
+ if (requestCount == 0) revert InvalidCmd();
46
+ cmd.numEvmCallRequestV1 = requestCount;
47
+ }
48
+
49
+ // decode the requests
50
+ for (uint16 i = 0; i < cmd.numEvmCallRequestV1; i++) {
51
+ uint8 requestVersion = uint8(_cmd[cursor]);
52
+ cursor += 1;
53
+ if (requestVersion != REQUEST_VERSION) revert InvalidVersion();
54
+
55
+ // skip appRequestLabel
56
+ cursor += 2;
57
+
58
+ uint16 resolverType = uint16(bytes2(_cmd[cursor:cursor + 2]));
59
+ cursor += 2;
60
+
61
+ if (resolverType == RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL) {
62
+ uint16 requestSize = uint16(bytes2(_cmd[cursor:cursor + 2]));
63
+ cursor += 2;
64
+
65
+ // decode the request in scope, depress stack too deep
66
+ {
67
+ uint256 requestCursor = cursor;
68
+ uint32 targetEid = uint32(bytes4(_cmd[requestCursor:requestCursor + 4]));
69
+ requestCursor += 4;
70
+
71
+ bool isBlockNum = uint8(_cmd[requestCursor]) == 1;
72
+ requestCursor += 1;
73
+
74
+ uint64 blockNumOrTimestamp = uint64(bytes8(_cmd[requestCursor:requestCursor + 8]));
75
+
76
+ _assertCmdTypeSupported(
77
+ targetEid,
78
+ isBlockNum,
79
+ blockNumOrTimestamp,
80
+ SupportedCmdTypesLib.CMD_V1__REQUEST_V1__EVM_CALL
81
+ );
82
+ }
83
+
84
+ if (cursor + requestSize > _cmd.length) revert InvalidCmd();
85
+ cursor += requestSize;
86
+ } else {
87
+ revert InvalidType();
88
+ }
89
+ }
90
+
91
+ // decode the compute if it exists
92
+ if (cursor < _cmd.length) {
93
+ uint8 computeVersion = uint8(_cmd[cursor]);
94
+ cursor += 1;
95
+ if (computeVersion != COMPUTE_VERSION) revert InvalidVersion();
96
+
97
+ uint16 computeType = uint16(bytes2(_cmd[cursor:cursor + 2]));
98
+ cursor += 2;
99
+ if (computeType != COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL) revert InvalidType();
100
+
101
+ uint8 computeSetting = uint8(_cmd[cursor]);
102
+ cursor += 1;
103
+
104
+ if (computeSetting == COMPUTE_SETTING_MAP_ONLY) {
105
+ cmd.evmCallComputeV1Map = true;
106
+ } else if (computeSetting == COMPUTE_SETTING_REDUCE_ONLY) {
107
+ cmd.evmCallComputeV1Reduce = true;
108
+ } else if (computeSetting == COMPUTE_SETTING_MAP_AND_REDUCE) {
109
+ cmd.evmCallComputeV1Map = true;
110
+ cmd.evmCallComputeV1Reduce = true;
111
+ } else {
112
+ revert InvalidType();
113
+ }
114
+
115
+ uint32 targetEid = uint32(bytes4(_cmd[cursor:cursor + 4]));
116
+ cursor += 4;
117
+
118
+ bool isBlockNum = uint8(_cmd[cursor]) == 1;
119
+ cursor += 1;
120
+
121
+ uint64 blockNumOrTimestamp = uint64(bytes8(_cmd[cursor:cursor + 8]));
122
+ cursor += 8;
123
+
124
+ _assertCmdTypeSupported(
125
+ targetEid,
126
+ isBlockNum,
127
+ blockNumOrTimestamp,
128
+ SupportedCmdTypesLib.CMD_V1__COMPUTE_V1__EVM_CALL
129
+ );
130
+
131
+ // assert the remaining length: confirmations(2), to(20)
132
+ cursor += 22;
133
+ }
134
+ if (cursor != _cmd.length) revert InvalidCmd();
135
+ }
136
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
6
+
7
+ struct SupportedCmdTypes {
8
+ mapping(uint32 => BitMap256) cmdTypes; // support options
9
+ }
10
+
11
+ using SupportedCmdTypesLib for SupportedCmdTypes global;
12
+
13
+ library SupportedCmdTypesLib {
14
+ // the max number of supported command types is 256
15
+ uint8 internal constant CMD_V1__REQUEST_V1__EVM_CALL = 0;
16
+ uint8 internal constant CMD_V1__COMPUTE_V1__EVM_CALL = 1;
17
+ uint8 internal constant CMD_V1__TIMESTAMP_VALIDATE = 2; // validate timestamp, to check if the timestamp is out of range
18
+ // more types can be added here in the future
19
+
20
+ error UnsupportedTargetEid();
21
+
22
+ function assertSupported(SupportedCmdTypes storage _self, uint32 _targetEid, uint8 _type) internal view {
23
+ if (!isSupported(_self, _targetEid, _type)) revert UnsupportedTargetEid();
24
+ }
25
+
26
+ function isSupported(SupportedCmdTypes storage _self, uint32 _targetEid, uint8 _type) internal view returns (bool) {
27
+ return _self.cmdTypes[_targetEid].get(_type);
28
+ }
29
+ }