@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,30 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ILayerZeroDVN } from "../interfaces/ILayerZeroDVN.sol";
6
+
7
+ contract DeadDVN is ILayerZeroDVN {
8
+ string internal constant ERROR_NOT_ALLOWED = "Please set your OApp's DVNs and/or Executor";
9
+
10
+ /// @dev for ULN301, ULN302 and more to assign job
11
+ function assignJob(AssignJobParam calldata, bytes calldata) external payable returns (uint256) {
12
+ revert(ERROR_NOT_ALLOWED);
13
+ }
14
+
15
+ /// @dev to support ULNv2
16
+ function assignJob(uint16, uint16, uint64, address) external pure returns (uint256) {
17
+ revert(ERROR_NOT_ALLOWED);
18
+ }
19
+
20
+ // ========================= View =========================
21
+
22
+ function getFee(uint32, uint64, address, bytes calldata) external pure returns (uint256) {
23
+ revert(ERROR_NOT_ALLOWED);
24
+ }
25
+
26
+ /// @dev to support ULNv2
27
+ function getFee(uint16, uint16, uint64, address) public pure returns (uint256) {
28
+ revert(ERROR_NOT_ALLOWED);
29
+ }
30
+ }
@@ -0,0 +1,135 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
6
+ import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
7
+
8
+ abstract contract MultiSig {
9
+ using EnumerableSet for EnumerableSet.AddressSet;
10
+
11
+ enum Errors {
12
+ NoError,
13
+ SignatureError,
14
+ DuplicatedSigner,
15
+ SignerNotInCommittee
16
+ }
17
+
18
+ EnumerableSet.AddressSet internal signerSet;
19
+ uint64 public quorum;
20
+
21
+ error MultiSig_OnlySigner();
22
+ error MultiSig_QuorumIsZero();
23
+ error MultiSig_SignersSizeIsLessThanQuorum(uint64 signersSize, uint64 quorum);
24
+ error MultiSig_UnorderedSigners();
25
+ error MultiSig_StateAlreadySet(address signer, bool active);
26
+ error MultiSig_StateNotSet(address signer, bool active);
27
+ error MultiSig_InvalidSigner();
28
+
29
+ event UpdateSigner(address _signer, bool _active);
30
+ event UpdateQuorum(uint64 _quorum);
31
+
32
+ modifier onlySigner() {
33
+ if (!isSigner(msg.sender)) {
34
+ revert MultiSig_OnlySigner();
35
+ }
36
+ _;
37
+ }
38
+
39
+ constructor(address[] memory _signers, uint64 _quorum) {
40
+ if (_quorum == 0) {
41
+ revert MultiSig_QuorumIsZero();
42
+ }
43
+ for (uint256 i = 0; i < _signers.length; i++) {
44
+ address signer = _signers[i];
45
+ if (signer == address(0)) {
46
+ revert MultiSig_InvalidSigner();
47
+ }
48
+ signerSet.add(signer);
49
+ }
50
+
51
+ uint64 _signerSize = uint64(signerSet.length());
52
+ if (_signerSize < _quorum) {
53
+ revert MultiSig_SignersSizeIsLessThanQuorum(_signerSize, _quorum);
54
+ }
55
+
56
+ quorum = _quorum;
57
+ }
58
+
59
+ function _setSigner(address _signer, bool _active) internal {
60
+ if (_active) {
61
+ if (_signer == address(0)) {
62
+ revert MultiSig_InvalidSigner();
63
+ }
64
+ if (!signerSet.add(_signer)) {
65
+ revert MultiSig_StateAlreadySet(_signer, _active);
66
+ }
67
+ } else {
68
+ if (!signerSet.remove(_signer)) {
69
+ revert MultiSig_StateNotSet(_signer, _active);
70
+ }
71
+ }
72
+
73
+ uint64 _signerSize = uint64(signerSet.length());
74
+ uint64 _quorum = quorum;
75
+ if (_signerSize < _quorum) {
76
+ revert MultiSig_SignersSizeIsLessThanQuorum(_signerSize, _quorum);
77
+ }
78
+ emit UpdateSigner(_signer, _active);
79
+ }
80
+
81
+ function _setQuorum(uint64 _quorum) internal {
82
+ if (_quorum == 0) {
83
+ revert MultiSig_QuorumIsZero();
84
+ }
85
+ uint64 _signerSize = uint64(signerSet.length());
86
+ if (_signerSize < _quorum) {
87
+ revert MultiSig_SignersSizeIsLessThanQuorum(_signerSize, _quorum);
88
+ }
89
+ quorum = _quorum;
90
+ emit UpdateQuorum(_quorum);
91
+ }
92
+
93
+ function verifySignatures(bytes32 _hash, bytes calldata _signatures) public view returns (bool, Errors) {
94
+ if (_signatures.length != uint256(quorum) * 65) {
95
+ return (false, Errors.SignatureError);
96
+ }
97
+
98
+ bytes32 messageDigest = _getEthSignedMessageHash(_hash);
99
+
100
+ address lastSigner = address(0); // There cannot be a signer with address 0.
101
+ for (uint256 i = 0; i < quorum; i++) {
102
+ // the quorum is guaranteed not to be zero in the constructor and setter
103
+ bytes calldata signature = _signatures[i * 65:(i + 1) * 65];
104
+ (address currentSigner, ECDSA.RecoverError error) = ECDSA.tryRecover(messageDigest, signature);
105
+
106
+ if (error != ECDSA.RecoverError.NoError) return (false, Errors.SignatureError);
107
+ if (currentSigner <= lastSigner) return (false, Errors.DuplicatedSigner); // prevent duplicate signatures, the signers must be ordered to sign the digest
108
+ if (!isSigner(currentSigner)) return (false, Errors.SignerNotInCommittee); // signature is not in committee
109
+ lastSigner = currentSigner;
110
+ }
111
+ return (true, Errors.NoError);
112
+ }
113
+
114
+ function _getEthSignedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
115
+ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
116
+ }
117
+
118
+ // ============================================== View ==============================================
119
+ function getSigners() public view returns (address[] memory) {
120
+ return signerSet.values();
121
+ }
122
+
123
+ // compatibility with the previous version
124
+ function signers(address _signer) public view returns (bool) {
125
+ return isSigner(_signer);
126
+ }
127
+
128
+ function isSigner(address _signer) public view returns (bool) {
129
+ return signerSet.contains(_signer);
130
+ }
131
+
132
+ function signerSize() public view returns (uint256) {
133
+ return signerSet.length();
134
+ }
135
+ }
@@ -0,0 +1,112 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
6
+
7
+ import { ILayerZeroReadDVN } from "../interfaces/ILayerZeroReadDVN.sol";
8
+ import { ReadCmdCodecV1 } from "../libs/ReadCmdCodecV1.sol";
9
+ import { ReadLib1002 } from "../readlib/ReadLib1002.sol";
10
+ import { SupportedCmdTypes } from "../libs/SupportedCmdTypes.sol";
11
+
12
+ contract SimpleReadDVN is ILayerZeroReadDVN {
13
+ struct SetSupportedCmdTypesParam {
14
+ uint32 targetEid;
15
+ BitMap256 types;
16
+ }
17
+
18
+ uint128 internal constant DENOMINATOR = 10 ** 18;
19
+ uint128 internal constant NATIVE_DECIMALS = 10 ** 18;
20
+
21
+ uint16 internal constant BPS_BASE = 10000;
22
+
23
+ address payable public immutable readLib;
24
+
25
+ // the usd fee should be usd * DENOMINATOR
26
+ uint128 internal evmCallRequestV1FeeUSD;
27
+ uint128 internal evmCallComputeV1MapFeeUSD;
28
+ uint128 internal evmCallComputeV1ReduceFeeUSD;
29
+
30
+ uint128 internal nativePriceUSD; // usd * DENOMINATOR
31
+
32
+ SupportedCmdTypes internal supportedCmdTypes;
33
+
34
+ constructor(address payable _readLib) {
35
+ readLib = _readLib;
36
+ }
37
+
38
+ function setSupportedCmdTypes(SetSupportedCmdTypesParam[] calldata _params) external {
39
+ for (uint256 i = 0; i < _params.length; i++) {
40
+ supportedCmdTypes.cmdTypes[_params[i].targetEid] = _params[i].types;
41
+ }
42
+ }
43
+
44
+ function assignJob(
45
+ address /*_sender*/,
46
+ bytes calldata /*_packetHeader*/,
47
+ bytes calldata _cmd,
48
+ bytes calldata /*_options*/
49
+ ) external payable returns (uint256) {
50
+ uint256 cmdFeeUSD = _estimateCmdFee(_cmd);
51
+ uint256 cmdFee = (cmdFeeUSD * NATIVE_DECIMALS) / nativePriceUSD;
52
+
53
+ return cmdFee;
54
+ }
55
+
56
+ function verify(bytes calldata _packetHeader, bytes32 _cmdHash, bytes32 _payloadHash) external {
57
+ ReadLib1002(readLib).verify(_packetHeader, _cmdHash, _payloadHash);
58
+ }
59
+
60
+ // ========================= View =========================
61
+
62
+ function getFee(
63
+ address /*_sender*/,
64
+ bytes calldata /*_packetHeader*/,
65
+ bytes calldata _cmd,
66
+ bytes calldata /*_options*/
67
+ ) external view returns (uint256) {
68
+ // cmdFeeUSD -> cmdFee native
69
+ uint256 cmdFeeUSD = _estimateCmdFee(_cmd);
70
+ uint256 cmdFee = (cmdFeeUSD * NATIVE_DECIMALS) / nativePriceUSD;
71
+
72
+ return cmdFee;
73
+ }
74
+
75
+ function setCmdFees(
76
+ uint128 _evmCallReqV1FeeUSD,
77
+ uint128 _evmCallComputeV1MapFeeUSD,
78
+ uint128 _evmCallComputeV1ReduceFeeUSD,
79
+ uint128 _nativePriceUSD
80
+ ) external {
81
+ evmCallRequestV1FeeUSD = _evmCallReqV1FeeUSD;
82
+ evmCallComputeV1MapFeeUSD = _evmCallComputeV1MapFeeUSD;
83
+ evmCallComputeV1ReduceFeeUSD = _evmCallComputeV1ReduceFeeUSD;
84
+ nativePriceUSD = _nativePriceUSD;
85
+ }
86
+
87
+ function getCmdFees() external view returns (uint128, uint128, uint128, uint128) {
88
+ return (evmCallRequestV1FeeUSD, evmCallComputeV1MapFeeUSD, evmCallComputeV1ReduceFeeUSD, nativePriceUSD);
89
+ }
90
+
91
+ function _estimateCmdFee(bytes calldata _cmd) internal view returns (uint256 fee) {
92
+ ReadCmdCodecV1.Cmd memory cmd = ReadCmdCodecV1.decode(_cmd, _assertCmdTypeSupported);
93
+ fee = cmd.numEvmCallRequestV1 * evmCallRequestV1FeeUSD;
94
+ if (cmd.evmCallComputeV1Map) {
95
+ fee += evmCallComputeV1MapFeeUSD * cmd.numEvmCallRequestV1;
96
+ }
97
+ if (cmd.evmCallComputeV1Reduce) {
98
+ fee += evmCallComputeV1ReduceFeeUSD;
99
+ }
100
+ }
101
+
102
+ function _assertCmdTypeSupported(
103
+ uint32 _targetEid,
104
+ bool /*_isBlockNum*/,
105
+ uint64 /*_blockNumOrTimestamp*/,
106
+ uint8 _cmdType
107
+ ) internal view {
108
+ supportedCmdTypes.assertSupported(_targetEid, _cmdType);
109
+ }
110
+
111
+ receive() external payable virtual {}
112
+ }
@@ -0,0 +1,151 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { IRouterClient } from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
6
+ import { IAny2EVMMessageReceiver } from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol";
7
+ import { Client } from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
8
+
9
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
10
+ import { ICCIPDVNAdapter } from "../../../interfaces/adapters/ICCIPDVNAdapter.sol";
11
+ import { ICCIPDVNAdapterFeeLib } from "../../../interfaces/adapters/ICCIPDVNAdapterFeeLib.sol";
12
+
13
+ /// @title CCIPDVNAdapter
14
+ /// @dev How CCIP DVN Adapter works:
15
+ /// 1. Estimate gas cost for the message on-chain by calling `getFee` on the Router contract.
16
+ /// refer to https://docs.chain.link/ccip/api-reference/i-router-client#getfee
17
+ /// 2. Call `ccipSend` on the Router contract to send the message.
18
+ /// refer to https://docs.chain.link/ccip/api-reference/i-router-client#ccipsend
19
+ /// @dev Recovery:
20
+ /// 1. If not enough gas paid, the message will be failed to execute on the destination chain, you can manually retry by calling `manuallyExecute` on the `OffRamp` contract.
21
+ /// refer to https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol#L222
22
+ contract CCIPDVNAdapter is DVNAdapterBase, IAny2EVMMessageReceiver, ICCIPDVNAdapter {
23
+ address private constant NATIVE_GAS_TOKEN_ADDRESS = address(0);
24
+
25
+ IRouterClient public immutable router;
26
+
27
+ mapping(uint32 dstEid => DstConfig) public dstConfig;
28
+ mapping(uint64 srcChainSelector => SrcConfig) public srcConfig;
29
+
30
+ constructor(address[] memory _admins, address _router) DVNAdapterBase(msg.sender, _admins, 12000) {
31
+ router = IRouterClient(_router);
32
+ }
33
+
34
+ // ========================= OnlyAdmin =========================
35
+ /// @notice sets configuration for destination chains
36
+ /// @param _params array of chain configurations
37
+ function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
38
+ for (uint256 i = 0; i < _params.length; i++) {
39
+ DstConfigParam calldata param = _params[i];
40
+
41
+ uint32 eid = param.eid % 30000;
42
+
43
+ // set once per chainSelector
44
+ // only one adapter per dvn that services both endpoint v1 and v2
45
+ // we standardize the eid stored here with mod 30000
46
+ if (dstConfig[eid].chainSelector == 0) {
47
+ dstConfig[eid].chainSelector = param.chainSelector;
48
+ dstConfig[eid].peer = param.peer;
49
+ srcConfig[param.chainSelector].eid = eid;
50
+ srcConfig[param.chainSelector].peer = param.peer;
51
+ }
52
+
53
+ dstConfig[eid].multiplierBps = param.multiplierBps;
54
+ dstConfig[eid].gas = param.gas;
55
+ }
56
+
57
+ emit DstConfigSet(_params);
58
+ }
59
+
60
+ // ========================= OnlyMessageLib =========================
61
+ function assignJob(
62
+ AssignJobParam calldata _param,
63
+ bytes calldata _options
64
+ ) external payable override onlyAcl(_param.sender) returns (uint256 totalFee) {
65
+ bytes32 receiveLib = _getAndAssertReceiveLib(msg.sender, _param.dstEid);
66
+
67
+ ICCIPDVNAdapterFeeLib.Param memory feeLibParam = ICCIPDVNAdapterFeeLib.Param(
68
+ _param.dstEid,
69
+ _param.confirmations,
70
+ _param.sender,
71
+ defaultMultiplierBps
72
+ );
73
+
74
+ DstConfig memory config = dstConfig[_param.dstEid % 30000];
75
+
76
+ bytes memory data = _encode(receiveLib, _param.packetHeader, _param.payloadHash);
77
+ Client.EVM2AnyMessage memory message = _createCCIPMessage(data, config.peer, config.gas);
78
+
79
+ IRouterClient ccipRouter = router;
80
+ uint256 ccipFee;
81
+ (ccipFee, totalFee) = ICCIPDVNAdapterFeeLib(workerFeeLib).getFeeOnSend(
82
+ feeLibParam,
83
+ config,
84
+ message,
85
+ _options,
86
+ ccipRouter
87
+ );
88
+
89
+ _assertBalanceAndWithdrawFee(msg.sender, ccipFee);
90
+
91
+ ccipRouter.ccipSend{ value: ccipFee }(config.chainSelector, message);
92
+ }
93
+
94
+ // ========================= OnlyRouter =========================
95
+ function ccipReceive(Client.Any2EVMMessage calldata _message) external {
96
+ if (msg.sender != address(router)) revert CCIPDVNAdapter_InvalidRouter(msg.sender);
97
+
98
+ SrcConfig memory config = srcConfig[_message.sourceChainSelector];
99
+
100
+ _assertPeer(_message.sourceChainSelector, _message.sender, config.peer);
101
+
102
+ _decodeAndVerify(config.eid, _message.data);
103
+ }
104
+
105
+ // ========================= View =========================
106
+ function getFee(
107
+ uint32 _dstEid,
108
+ uint64 _confirmations,
109
+ address _sender,
110
+ bytes calldata _options
111
+ ) external view override onlyAcl(_sender) returns (uint256 totalFee) {
112
+ ICCIPDVNAdapterFeeLib.Param memory feeLibParam = ICCIPDVNAdapterFeeLib.Param(
113
+ _dstEid,
114
+ _confirmations,
115
+ _sender,
116
+ defaultMultiplierBps
117
+ );
118
+
119
+ DstConfig memory config = dstConfig[_dstEid % 30000];
120
+
121
+ bytes memory data = _encodeEmpty();
122
+ Client.EVM2AnyMessage memory message = _createCCIPMessage(data, config.peer, config.gas);
123
+
124
+ totalFee = ICCIPDVNAdapterFeeLib(workerFeeLib).getFee(feeLibParam, config, message, _options, router);
125
+ }
126
+
127
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
128
+ return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || super.supportsInterface(interfaceId);
129
+ }
130
+
131
+ // ========================= Internal =========================
132
+ function _createCCIPMessage(
133
+ bytes memory _data,
134
+ bytes memory _receiver,
135
+ uint256 _gas
136
+ ) private pure returns (Client.EVM2AnyMessage memory message) {
137
+ message = Client.EVM2AnyMessage({
138
+ receiver: _receiver,
139
+ data: _data,
140
+ tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array indicating no tokens are being sent
141
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({ gasLimit: _gas, strict: false })),
142
+ feeToken: NATIVE_GAS_TOKEN_ADDRESS
143
+ });
144
+ }
145
+
146
+ function _assertPeer(uint64 _sourceChainSelector, bytes memory _sourceAddress, bytes memory peer) private pure {
147
+ if (keccak256(_sourceAddress) != keccak256(peer)) {
148
+ revert CCIPDVNAdapter_UntrustedPeer(_sourceChainSelector, _sourceAddress);
149
+ }
150
+ }
151
+ }
@@ -0,0 +1,71 @@
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 { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
7
+ import { Client } from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
8
+ import { IRouterClient } from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
9
+
10
+ import { ICCIPDVNAdapter } from "../../../interfaces/adapters/ICCIPDVNAdapter.sol";
11
+ import { ICCIPDVNAdapterFeeLib } from "../../../interfaces/adapters/ICCIPDVNAdapterFeeLib.sol";
12
+
13
+ contract CCIPDVNAdapterFeeLib is OwnableUpgradeable, Proxied, ICCIPDVNAdapterFeeLib {
14
+ uint16 internal constant BPS_DENOMINATOR = 10000;
15
+
16
+ mapping(uint32 dstEid => DstConfig) public dstConfig;
17
+
18
+ function initialize() external proxied initializer {
19
+ __Ownable_init();
20
+ }
21
+
22
+ // ================================ OnlyOwner ===============================
23
+ function setDstConfig(DstConfigParam[] calldata _param) external onlyOwner {
24
+ for (uint256 i = 0; i < _param.length; i++) {
25
+ DstConfigParam calldata param = _param[i];
26
+
27
+ dstConfig[param.dstEid] = DstConfig({ floorMarginUSD: param.floorMarginUSD });
28
+ }
29
+
30
+ emit DstConfigSet(_param);
31
+ }
32
+
33
+ // ================================ External ================================
34
+ function getFeeOnSend(
35
+ Param calldata _params,
36
+ ICCIPDVNAdapter.DstConfig calldata _dstConfig,
37
+ Client.EVM2AnyMessage calldata _message,
38
+ bytes calldata _options,
39
+ IRouterClient _router
40
+ ) external payable returns (uint256 ccipFee, uint256 totalFee) {
41
+ if (_dstConfig.gas == 0) revert CCIPDVNAdapter_EidNotSupported(_params.dstEid);
42
+ if (_options.length > 0) revert CCIPDVNAdapter_OptionsUnsupported();
43
+
44
+ ccipFee = _router.getFee(_dstConfig.chainSelector, _message);
45
+ totalFee = _applyPremium(_dstConfig.multiplierBps, _params.defaultMultiplierBps, ccipFee);
46
+ }
47
+
48
+ function getFee(
49
+ Param calldata _params,
50
+ ICCIPDVNAdapter.DstConfig calldata _dstConfig,
51
+ Client.EVM2AnyMessage calldata _message,
52
+ bytes calldata _options,
53
+ IRouterClient _router
54
+ ) external view returns (uint256 totalFee) {
55
+ if (_dstConfig.gas == 0) revert CCIPDVNAdapter_EidNotSupported(_params.dstEid);
56
+ if (_options.length > 0) revert CCIPDVNAdapter_OptionsUnsupported();
57
+
58
+ totalFee = _router.getFee(_dstConfig.chainSelector, _message);
59
+ totalFee = _applyPremium(_dstConfig.multiplierBps, _params.defaultMultiplierBps, totalFee);
60
+ }
61
+
62
+ // ================================ Internal ================================
63
+ function _applyPremium(
64
+ uint16 _multiplierBps,
65
+ uint16 _defaultMultiplierBps,
66
+ uint256 _fee
67
+ ) internal pure returns (uint256 fee) {
68
+ uint256 multiplier = _multiplierBps == 0 ? _defaultMultiplierBps : _multiplierBps;
69
+ fee = (_fee * multiplier) / BPS_DENOMINATOR;
70
+ }
71
+ }
@@ -0,0 +1,114 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
6
+ import { ISendLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
7
+
8
+ import { ILayerZeroDVN } from "../../interfaces/ILayerZeroDVN.sol";
9
+ import { Worker } from "../../../Worker.sol";
10
+ import { DVNAdapterMessageCodec } from "./libs/DVNAdapterMessageCodec.sol";
11
+
12
+ interface ISendLibBase {
13
+ function fees(address _worker) external view returns (uint256);
14
+ }
15
+
16
+ interface IReceiveUln {
17
+ function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external;
18
+ }
19
+
20
+ struct ReceiveLibParam {
21
+ address sendLib;
22
+ uint32 dstEid;
23
+ bytes32 receiveLib;
24
+ }
25
+
26
+ /// @title SendDVNAdapterBase
27
+ /// @notice base contract for DVN adapters
28
+ /// @dev limitations:
29
+ /// - doesn't accept alt token
30
+ /// - doesn't respect block confirmations
31
+ abstract contract DVNAdapterBase is Worker, ILayerZeroDVN {
32
+ // --- Errors ---
33
+ error DVNAdapter_InsufficientBalance(uint256 actual, uint256 requested);
34
+ error DVNAdapter_NotImplemented();
35
+ error DVNAdapter_MissingRecieveLib(address sendLib, uint32 dstEid);
36
+
37
+ event ReceiveLibsSet(ReceiveLibParam[] params);
38
+
39
+ /// @dev on change of application config, dvn adapters will not perform any additional verification
40
+ /// @dev to avoid messages from being stuck, all verifications from adapters will be done with the maximum possible confirmations
41
+ uint64 internal constant MAX_CONFIRMATIONS = type(uint64).max;
42
+
43
+ /// @dev receive lib to call verify() on at destination
44
+ mapping(address sendLib => mapping(uint32 dstEid => bytes32 receiveLib)) public receiveLibs;
45
+
46
+ constructor(
47
+ address _roleAdmin,
48
+ address[] memory _admins,
49
+ uint16 _defaultMultiplierBps
50
+ ) Worker(new address[](0), address(0x0), _defaultMultiplierBps, _roleAdmin, _admins) {}
51
+
52
+ // ========================= OnlyAdmin =========================
53
+ /// @notice sets receive lib for destination chains
54
+ /// @dev DEFAULT_ADMIN_ROLE can set MESSAGE_LIB_ROLE for sendLibs and use below function to set receiveLibs
55
+ function setReceiveLibs(ReceiveLibParam[] calldata _params) external onlyRole(DEFAULT_ADMIN_ROLE) {
56
+ for (uint256 i = 0; i < _params.length; i++) {
57
+ ReceiveLibParam calldata param = _params[i];
58
+ receiveLibs[param.sendLib][param.dstEid] = param.receiveLib;
59
+ }
60
+
61
+ emit ReceiveLibsSet(_params);
62
+ }
63
+
64
+ // ========================= Internal =========================
65
+ function _getAndAssertReceiveLib(address _sendLib, uint32 _dstEid) internal view returns (bytes32 lib) {
66
+ lib = receiveLibs[_sendLib][_dstEid];
67
+ if (lib == bytes32(0)) revert DVNAdapter_MissingRecieveLib(_sendLib, _dstEid);
68
+ }
69
+
70
+ function _encode(
71
+ bytes32 _receiveLib,
72
+ bytes memory _packetHeader,
73
+ bytes32 _payloadHash
74
+ ) internal pure returns (bytes memory) {
75
+ return DVNAdapterMessageCodec.encode(_receiveLib, _packetHeader, _payloadHash);
76
+ }
77
+
78
+ function _encodeEmpty() internal pure returns (bytes memory) {
79
+ return
80
+ DVNAdapterMessageCodec.encode(bytes32(0), new bytes(DVNAdapterMessageCodec.PACKET_HEADER_SIZE), bytes32(0));
81
+ }
82
+
83
+ function _decodeAndVerify(uint32 _srcEid, bytes calldata _payload) internal {
84
+ require((DVNAdapterMessageCodec.srcEid(_payload) % 30000) == _srcEid, "DVNAdapterBase: invalid srcEid");
85
+
86
+ (address receiveLib, bytes memory packetHeader, bytes32 payloadHash) = DVNAdapterMessageCodec.decode(_payload);
87
+
88
+ IReceiveUln(receiveLib).verify(packetHeader, payloadHash, MAX_CONFIRMATIONS);
89
+ }
90
+
91
+ function _withdrawFeeFromSendLib(address _sendLib, address _to) internal {
92
+ uint256 fee = ISendLibBase(_sendLib).fees(address(this));
93
+ if (fee > 0) {
94
+ ISendLib(_sendLib).withdrawFee(_to, fee);
95
+ emit Withdraw(_sendLib, _to, fee);
96
+ }
97
+ }
98
+
99
+ function _assertBalanceAndWithdrawFee(address _sendLib, uint256 _messageFee) internal {
100
+ uint256 balance = address(this).balance;
101
+ if (balance < _messageFee) {
102
+ // withdraw all fees from the sendLib if balance is insufficient
103
+ _withdrawFeeFromSendLib(_sendLib, address(this));
104
+
105
+ // check balance again
106
+ balance = address(this).balance;
107
+ // revert if balance is still insufficient, need to transfer more funds manually to the adapter
108
+ if (balance < _messageFee) revert DVNAdapter_InsufficientBalance(balance, _messageFee);
109
+ }
110
+ }
111
+
112
+ /// @dev to receive refund
113
+ receive() external payable {}
114
+ }