@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,126 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { IInbox } from "@arbitrum/nitro-contracts/src/bridge/IInbox.sol";
6
+
7
+ import { ArbitrumDVNAdapterL2 } from "./ArbitrumDVNAdapterL2.sol";
8
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
9
+ import { DVNAdapterMessageCodec } from "../libs/DVNAdapterMessageCodec.sol";
10
+
11
+ contract ArbitrumDVNAdapterL1 is DVNAdapterBase {
12
+ // --- Config Struct ---
13
+ struct DstConfig {
14
+ uint16 multiplierBps;
15
+ uint256 maxSubmissionCost;
16
+ uint256 gasLimit;
17
+ uint256 maxFeePerGas;
18
+ }
19
+
20
+ // --- Events ---
21
+ event RetryableTicketCreated(uint256 indexed ticketId);
22
+ error OnlyArbitrum();
23
+
24
+ uint32 public immutable arbitrumEid; // eid % 30000 (v1 eid)
25
+ IInbox public immutable inbox;
26
+
27
+ address public peer; // L2 adapter
28
+ DstConfig public dstConfig;
29
+
30
+ constructor(
31
+ address[] memory _admins,
32
+ uint32 _arbitrumEid,
33
+ address _inbox
34
+ ) DVNAdapterBase(msg.sender, _admins, 12000) {
35
+ arbitrumEid = _arbitrumEid; // eid % 30000 (v1 eid)
36
+ inbox = IInbox(_inbox);
37
+ }
38
+
39
+ // --- Admin ---
40
+ function setPeer(address _peer) external onlyRole(ADMIN_ROLE) {
41
+ peer = _peer;
42
+ }
43
+
44
+ function setDstConfig(
45
+ uint16 _multiplierBps,
46
+ uint256 _maxSubmissionCost,
47
+ uint256 _gasLimit,
48
+ uint256 _maxFeePerGas
49
+ ) external onlyRole(ADMIN_ROLE) {
50
+ dstConfig = DstConfig({
51
+ multiplierBps: _multiplierBps,
52
+ maxSubmissionCost: _maxSubmissionCost,
53
+ gasLimit: _gasLimit,
54
+ maxFeePerGas: _maxFeePerGas
55
+ });
56
+ }
57
+
58
+ // --- Send ---
59
+ function assignJob(
60
+ AssignJobParam calldata _param,
61
+ bytes calldata /*_options*/
62
+ ) external payable override onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_param.sender) returns (uint256 fee) {
63
+ DstConfig storage config = dstConfig;
64
+ fee = _getArbitrumFee(_param.dstEid, config);
65
+
66
+ bytes memory payload = abi.encodeWithSelector(
67
+ ArbitrumDVNAdapterL2.verify.selector,
68
+ DVNAdapterMessageCodec.encode(
69
+ receiveLibs[msg.sender][_param.dstEid],
70
+ _param.packetHeader,
71
+ _param.payloadHash
72
+ )
73
+ );
74
+
75
+ // fee estimation: https://github.com/OffchainLabs/arbitrum-sdk/blob/main/src/lib/message/L1ToL2MessageCreator.ts#L52
76
+ uint256 ticketID = inbox.createRetryableTicket{ value: fee }(
77
+ peer,
78
+ 0,
79
+ config.maxSubmissionCost,
80
+ peer,
81
+ peer,
82
+ config.gasLimit,
83
+ config.maxFeePerGas,
84
+ payload
85
+ );
86
+ emit RetryableTicketCreated(ticketID);
87
+
88
+ // adjust fee based on multiplier
89
+ // if (workerFeeLib != address(0)) {
90
+ // fee = IDVNAdapterFeeLib(workerFeeLib).getFee(
91
+ // _param.dstEid,
92
+ // _param.sender,
93
+ // defaultMultiplierBps,
94
+ // config.multiplierBps,
95
+ // fee
96
+ // );
97
+ // }
98
+ }
99
+
100
+ // --- View ---
101
+ function getFee(
102
+ uint32 _dstEid,
103
+ uint64 /*_confirmations*/,
104
+ address _sender,
105
+ bytes calldata /*_options*/
106
+ ) public view override onlyAcl(_sender) returns (uint256 fee) {
107
+ DstConfig storage config = dstConfig;
108
+ fee = _getArbitrumFee(_dstEid, config);
109
+
110
+ // adjust fee based on multiplier
111
+ // if (workerFeeLib != address(0)) {
112
+ // fee = IDVNAdapterFeeLib(workerFeeLib).getFee(
113
+ // _dstEid,
114
+ // _sender,
115
+ // defaultMultiplierBps,
116
+ // config.multiplierBps,
117
+ // fee
118
+ // );
119
+ // }
120
+ }
121
+
122
+ function _getArbitrumFee(uint32 _dstEid, DstConfig storage _dstConfig) internal view returns (uint256 fee) {
123
+ if (_dstEid % 30000 != arbitrumEid) revert OnlyArbitrum();
124
+ fee = _dstConfig.maxSubmissionCost + _dstConfig.gasLimit * _dstConfig.maxFeePerGas;
125
+ }
126
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { AddressAliasHelper } from "@arbitrum/nitro-contracts/src/libraries/AddressAliasHelper.sol";
6
+
7
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
8
+
9
+ contract ArbitrumDVNAdapterL2 is DVNAdapterBase {
10
+ // --- Errors ---
11
+ error UntrustedPeer(address peer);
12
+
13
+ // --- Events ---
14
+ event PeerSet(address peer);
15
+
16
+ // --- Variables ---
17
+ address public peer; // L1 adapter
18
+
19
+ constructor(address[] memory _admins) DVNAdapterBase(msg.sender, _admins, 12000) {}
20
+
21
+ // --- Admin ---
22
+ function setPeer(address _peer) external onlyRole(ADMIN_ROLE) {
23
+ peer = _peer;
24
+ emit PeerSet(_peer);
25
+ }
26
+
27
+ // --- Send ---
28
+ function assignJob(
29
+ AssignJobParam calldata /*_param*/,
30
+ bytes calldata /*_options*/
31
+ ) external payable override returns (uint256) {
32
+ revert DVNAdapter_NotImplemented();
33
+ }
34
+
35
+ function getFee(
36
+ uint32 /*_dstEid*/,
37
+ uint64 /*_confirmations*/,
38
+ address /*_sender*/,
39
+ bytes calldata /*_options*/
40
+ ) external pure override returns (uint256) {
41
+ revert DVNAdapter_NotImplemented();
42
+ }
43
+
44
+ // --- Receive ---
45
+ function verify(bytes calldata _payload) external {
46
+ // To check that message came from L1, we check that the sender is the L1 contract's L2 alias.
47
+ if (msg.sender != AddressAliasHelper.applyL1ToL2Alias(peer)) revert UntrustedPeer(msg.sender);
48
+ _decodeAndVerify(0, _payload); //todo: fix
49
+ }
50
+ }
@@ -0,0 +1,4 @@
1
+ https://github.com/ava-labs/teleporter/blob/main/contracts/src/Teleporter/README.md
2
+ https://github.com/ava-labs/teleporter/blob/main/contracts/src/CrossChainApplications/ExampleMessenger/ExampleCrossChainMessenger.sol
3
+ https://github.com/ava-labs/public-avalanche-sdks/tree/main/apps/teleporter-demo
4
+ https://github.com/ava-labs/xsvm
@@ -0,0 +1,152 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { AxelarExecutable } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
6
+ import { ISendLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
7
+
8
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
9
+ import { IAxelarDVNAdapter } from "../../../interfaces/adapters/IAxelarDVNAdapter.sol";
10
+ import { IAxelarDVNAdapterFeeLib } from "../../../interfaces/adapters/IAxelarDVNAdapterFeeLib.sol";
11
+
12
+ interface ISendLibBase {
13
+ function fees(address _worker) external view returns (uint256);
14
+ }
15
+
16
+ /// @title AxelarDVNAdapter
17
+ /// @dev How Axelar DVN Adapter works:
18
+ /// 1. Estimate gas fee off-chain using the Axelar SDK.
19
+ /// refer to https://docs.axelar.dev/dev/axelarjs-sdk/axelar-query-api#estimategasfee
20
+ /// 2. Pay gas fee by calling `payNativeGasForContractCall` on the AxelarGasService contract.
21
+ /// refer to https://docs.axelar.dev/dev/general-message-passing/gas-services/pay-gas#paynativegasforcontractcall
22
+ /// 3. Send message by calling `callContract` on the AxelarGateway contract.
23
+ /// refer to https://docs.axelar.dev/dev/general-message-passing/gmp-messages#call-a-contract-on-chain-b-from-chain-a
24
+ /// 4. Refund surplus gas fee asynchronously.
25
+ /// refer to https://docs.axelar.dev/dev/general-message-passing/gas-services/refund
26
+ /// @dev Recovery:
27
+ /// 1. If not enough gas fee is paid, the message will be hangup on source chain and can `add gas` to retry.
28
+ /// refer to https://docs.axelar.dev/dev/general-message-passing/recovery#increase-gas-payment-to-the-gas-receiver-on-the-source-chain
29
+ /// 2. If the message is not executed on the destination chain, you can manually retry by calling `execute` on the `ReceiveAxelarDVNAdapter` contract.
30
+ /// refer to https://docs.axelar.dev/dev/general-message-passing/recovery#manually-execute-a-transfer
31
+ /// @dev As the Gas is estimated off-chain, we need to update the gas fee periodically on-chain by calling `setNativeGasFee` with the new fee.
32
+ contract AxelarDVNAdapter is DVNAdapterBase, AxelarExecutable, IAxelarDVNAdapter {
33
+ mapping(string srcChainName => SrcConfig) public srcConfig; // by chain name
34
+ mapping(uint32 dstEid => DstConfig) public dstConfig; // by dstEid
35
+
36
+ // set default multiplier to 2.5x
37
+ constructor(
38
+ address[] memory _admins,
39
+ address _gateway
40
+ ) AxelarExecutable(_gateway) DVNAdapterBase(msg.sender, _admins, 10000) {}
41
+
42
+ // ========================= OnlyAdmin =========================
43
+ function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
44
+ for (uint256 i = 0; i < _params.length; i++) {
45
+ DstConfigParam calldata param = _params[i];
46
+
47
+ uint32 eid = param.eid % 30000;
48
+
49
+ // set once per chainName
50
+ // only one adapter per dvn that services both endpoint v1 and v2
51
+ // we standardize the eid stored here with mod 30000
52
+ if (bytes(dstConfig[eid].chainName).length == 0) {
53
+ dstConfig[eid].chainName = param.chainName;
54
+ dstConfig[eid].peer = param.peer;
55
+ srcConfig[param.chainName].eid = eid;
56
+ srcConfig[param.chainName].peer = param.peer;
57
+ }
58
+
59
+ dstConfig[eid].multiplierBps = param.multiplierBps;
60
+ dstConfig[eid].nativeGasFee = param.nativeGasFee;
61
+ }
62
+
63
+ emit DstConfigSet(_params);
64
+ }
65
+
66
+ /// @notice sets message fee in native gas for destination chains.
67
+ /// @dev Axelar does not support quoting fee on-chain. Instead, the fee needs to be obtained off-chain by querying through the Axelar SDK.
68
+ /// @dev The fee may change over time when token prices change, requiring admins to monitor and make necessary updates to reflect the actual fee.
69
+ /// @dev Adding a buffer to the required fee is advisable. Any surplus fee will be refunded asynchronously if it exceeds the necessary amount.
70
+ /// https://docs.axelar.dev/dev/general-message-passing/gas-services/pay-gas
71
+ /// https://github.com/axelarnetwork/axelarjs/blob/070c8fe061f1082e79772fdc5c4675c0237bbba2/packages/api/src/axelar-query/isomorphic.ts#L54
72
+ /// https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d4536599321774927bf9716178a9e360f8e0efac/contracts/gas-service/AxelarGasService.sol#L403
73
+ function setNativeGasFee(NativeGasFeeParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
74
+ for (uint256 i = 0; i < _params.length; i++) {
75
+ NativeGasFeeParam calldata param = _params[i];
76
+ dstConfig[param.dstEid % 30000].nativeGasFee = param.nativeGasFee;
77
+ }
78
+ emit NativeGasFeeSet(_params);
79
+ }
80
+
81
+ // ========================= OnlyWorkerFeeLib =========================
82
+ function withdrawToFeeLib(address _sendLib) external {
83
+ if (msg.sender != workerFeeLib) revert AxelarDVNAdapter_OnlyWorkerFeeLib();
84
+
85
+ _withdrawFeeFromSendLib(_sendLib, workerFeeLib);
86
+ }
87
+
88
+ // ========================= OnlyMessageLib =========================
89
+ function assignJob(
90
+ AssignJobParam calldata _param,
91
+ bytes calldata _options
92
+ ) external payable override onlyAcl(_param.sender) returns (uint totalFee) {
93
+ bytes32 receiveLib = _getAndAssertReceiveLib(msg.sender, _param.dstEid);
94
+
95
+ IAxelarDVNAdapterFeeLib.Param memory feeLibParam = IAxelarDVNAdapterFeeLib.Param({
96
+ dstEid: _param.dstEid,
97
+ confirmations: _param.confirmations,
98
+ sender: _param.sender,
99
+ defaultMultiplierBps: defaultMultiplierBps
100
+ });
101
+ DstConfig memory config = dstConfig[_param.dstEid % 30000];
102
+
103
+ bytes memory payload = _encode(receiveLib, _param.packetHeader, _param.payloadHash);
104
+
105
+ totalFee = IAxelarDVNAdapterFeeLib(workerFeeLib).getFeeOnSend(
106
+ feeLibParam,
107
+ config,
108
+ payload,
109
+ _options,
110
+ msg.sender
111
+ );
112
+
113
+ gateway.callContract(config.chainName, config.peer, payload);
114
+ }
115
+
116
+ // ========================= View =========================
117
+ function getFee(
118
+ uint32 _dstEid,
119
+ uint64 _confirmations,
120
+ address _sender,
121
+ bytes calldata _options
122
+ ) external view override returns (uint256 totalFee) {
123
+ IAxelarDVNAdapterFeeLib.Param memory feeLibParam = IAxelarDVNAdapterFeeLib.Param(
124
+ _dstEid,
125
+ _confirmations,
126
+ _sender,
127
+ defaultMultiplierBps
128
+ );
129
+
130
+ totalFee = IAxelarDVNAdapterFeeLib(workerFeeLib).getFee(feeLibParam, dstConfig[_dstEid % 30000], _options);
131
+ }
132
+
133
+ // ========================= Internal =========================
134
+ function _execute(
135
+ string calldata _sourceChain,
136
+ string calldata _sourceAddress,
137
+ bytes calldata _payload
138
+ ) internal override {
139
+ SrcConfig memory config = srcConfig[_sourceChain];
140
+
141
+ // assert peer is the same as the source chain
142
+ _assertPeer(_sourceChain, _sourceAddress, config.peer);
143
+
144
+ _decodeAndVerify(config.eid, _payload);
145
+ }
146
+
147
+ function _assertPeer(string memory _sourceChain, string memory _sourceAddress, string memory peer) private pure {
148
+ if (keccak256(bytes(_sourceAddress)) != keccak256(bytes(peer))) {
149
+ revert AxelarDVNAdapter_UntrustedPeer(_sourceChain, _sourceAddress);
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,127 @@
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 { IAxelarGasService } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";
8
+ import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
9
+
10
+ import { IAxelarDVNAdapter } from "../../../interfaces/adapters/IAxelarDVNAdapter.sol";
11
+ import { IAxelarDVNAdapterFeeLib } from "../../../interfaces/adapters/IAxelarDVNAdapterFeeLib.sol";
12
+ import { ILayerZeroPriceFeed } from "../../../../interfaces/ILayerZeroPriceFeed.sol";
13
+
14
+ contract AxelarDVNAdapterFeeLib is OwnableUpgradeable, Proxied, IAxelarDVNAdapterFeeLib {
15
+ uint16 internal constant BPS_DENOMINATOR = 10000;
16
+
17
+ /// @dev to be applied to native gas fee before sending to Axelar Gas Service
18
+ uint16 public nativeGasFeeMultiplierBps;
19
+
20
+ IAxelarDVNAdapter public dvn;
21
+ IAxelarGasService public gasService;
22
+ ILayerZeroPriceFeed public priceFeed;
23
+
24
+ mapping(uint32 dstEid => DstConfig) public dstConfig;
25
+
26
+ function initialize(
27
+ address _gasService,
28
+ address _dvn,
29
+ uint16 _nativeGasFeeMultiplierBps
30
+ ) external proxied initializer {
31
+ __Ownable_init();
32
+ gasService = IAxelarGasService(_gasService);
33
+ dvn = IAxelarDVNAdapter(_dvn);
34
+ nativeGasFeeMultiplierBps = _nativeGasFeeMultiplierBps;
35
+ }
36
+
37
+ // ================================ OnlyOwner ================================
38
+ function withdrawToken(address _token, address _to, uint256 _amount) external onlyOwner {
39
+ // transfers native if _token is address(0x0)
40
+ Transfer.nativeOrToken(_token, _to, _amount);
41
+ emit TokenWithdrawn(_token, _to, _amount);
42
+ }
43
+
44
+ function setGasService(address _gasService) external onlyOwner {
45
+ gasService = IAxelarGasService(_gasService);
46
+ emit GasServiceSet(_gasService);
47
+ }
48
+
49
+ function setPriceFeed(address _priceFeed) external onlyOwner {
50
+ priceFeed = ILayerZeroPriceFeed(_priceFeed);
51
+ emit PriceFeedSet(_priceFeed);
52
+ }
53
+
54
+ function setDstConfig(DstConfigParam[] calldata _param) external onlyOwner {
55
+ for (uint256 i = 0; i < _param.length; i++) {
56
+ DstConfigParam calldata param = _param[i];
57
+ dstConfig[param.dstEid] = DstConfig({ gas: param.gas, floorMarginUSD: param.floorMarginUSD });
58
+ }
59
+ emit DstConfigSet(_param);
60
+ }
61
+
62
+ function setNativeGasFeeMultiplierBps(uint16 _multiplierBps) external onlyOwner {
63
+ nativeGasFeeMultiplierBps = _multiplierBps;
64
+ emit NativeGasFeeMultiplierBpsSet(_multiplierBps);
65
+ }
66
+
67
+ // ================================ External ================================
68
+ function getFeeOnSend(
69
+ Param calldata _param,
70
+ IAxelarDVNAdapter.DstConfig calldata _dstConfig,
71
+ bytes memory _payload,
72
+ bytes calldata _options,
73
+ address _sendLib
74
+ ) external payable returns (uint256 totalFee) {
75
+ if (_dstConfig.nativeGasFee == 0) revert AxelarDVNAdapter_EidNotSupported(_param.dstEid);
76
+ if (_options.length > 0) revert AxelarDVNAdapter_OptionsUnsupported();
77
+
78
+ totalFee = _applyPremium(_dstConfig.multiplierBps, _param.defaultMultiplierBps, _dstConfig.nativeGasFee);
79
+
80
+ uint256 feeToAxelar = _getAxelarFeeWithBuffer(_dstConfig.nativeGasFee);
81
+ // withdraw from uln to fee lib if not enough balance
82
+ uint256 balance = address(this).balance;
83
+ if (balance < feeToAxelar) {
84
+ dvn.withdrawToFeeLib(_sendLib);
85
+
86
+ // revert if still not enough
87
+ balance = address(this).balance;
88
+ if (balance < feeToAxelar) revert AxelarDVNAdapter_InsufficientBalance(balance, feeToAxelar);
89
+ }
90
+
91
+ // pay axelar gas service
92
+ gasService.payNativeGasForContractCall{ value: feeToAxelar }(
93
+ msg.sender, // sender
94
+ _dstConfig.chainName, // destinationChain
95
+ _dstConfig.peer, // destinationAddress
96
+ _payload, // payload
97
+ address(this) // refundAddress
98
+ );
99
+ }
100
+
101
+ function getFee(
102
+ Param calldata _param,
103
+ IAxelarDVNAdapter.DstConfig calldata _dstConfig,
104
+ bytes calldata _options
105
+ ) external pure returns (uint256 totalFee) {
106
+ if (_dstConfig.nativeGasFee == 0) revert AxelarDVNAdapter_EidNotSupported(_param.dstEid);
107
+ if (_options.length > 0) revert AxelarDVNAdapter_OptionsUnsupported();
108
+
109
+ totalFee = _applyPremium(_dstConfig.multiplierBps, _param.defaultMultiplierBps, _dstConfig.nativeGasFee);
110
+ }
111
+
112
+ // ================================ Internal ================================
113
+ function _getAxelarFeeWithBuffer(uint256 _nativeGasFee) internal view returns (uint256) {
114
+ return (_nativeGasFee * nativeGasFeeMultiplierBps) / BPS_DENOMINATOR;
115
+ }
116
+
117
+ function _applyPremium(
118
+ uint16 multiplierBps,
119
+ uint16 defaultMultiplierBps,
120
+ uint256 fee
121
+ ) internal pure returns (uint256) {
122
+ uint256 multiplier = multiplierBps == 0 ? defaultMultiplierBps : multiplierBps;
123
+ return (fee * multiplier) / BPS_DENOMINATOR;
124
+ }
125
+
126
+ receive() external payable {}
127
+ }
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: LZBL-1.2
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
6
+
7
+ library DVNAdapterMessageCodec {
8
+ using AddressCast for bytes32;
9
+
10
+ error DVNAdapter_InvalidMessageSize();
11
+
12
+ uint256 private constant RECEIVE_LIB_OFFSET = 0;
13
+ uint256 private constant PAYLOAD_HASH_OFFSET = 32;
14
+ uint256 private constant PACKET_HEADER_OFFSET = 64;
15
+ uint256 private constant SRC_EID_OFFSET = 73; // 64 + 1 + 8
16
+
17
+ uint256 internal constant PACKET_HEADER_SIZE = 81; // version(uint8) + nonce(uint64) + path(uint32,bytes32,uint32,bytes32)
18
+ uint256 internal constant MESSAGE_SIZE = 32 + 32 + PACKET_HEADER_SIZE; // receive_lib(bytes32) + payloadHash(bytes32) + packetHeader
19
+
20
+ function encode(
21
+ bytes32 _receiveLib,
22
+ bytes memory _packetHeader,
23
+ bytes32 _payloadHash
24
+ ) internal pure returns (bytes memory payload) {
25
+ return abi.encodePacked(_receiveLib, _payloadHash, _packetHeader);
26
+ }
27
+
28
+ function decode(
29
+ bytes calldata _message
30
+ ) internal pure returns (address receiveLib, bytes memory packetHeader, bytes32 payloadHash) {
31
+ if (_message.length != MESSAGE_SIZE) revert DVNAdapter_InvalidMessageSize();
32
+
33
+ receiveLib = bytes32(_message[RECEIVE_LIB_OFFSET:PAYLOAD_HASH_OFFSET]).toAddress();
34
+ payloadHash = bytes32(_message[PAYLOAD_HASH_OFFSET:PACKET_HEADER_OFFSET]);
35
+ packetHeader = _message[PACKET_HEADER_OFFSET:];
36
+ }
37
+
38
+ function srcEid(bytes calldata _message) internal pure returns (uint32) {
39
+ return uint32(bytes4(_message[SRC_EID_OFFSET:SRC_EID_OFFSET + 4]));
40
+ }
41
+ }
@@ -0,0 +1,86 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol";
6
+
7
+ import { OptimismDVNAdapterL2 } from "./OptimismDVNAdapterL2.sol";
8
+ import { DVNAdapterMessageCodec } from "../libs/DVNAdapterMessageCodec.sol";
9
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
10
+
11
+ /// @title OptimismDVNAdapterL1
12
+ /// @dev How Optimism DVN adapter works:
13
+ /// 1. call `sendMessage` on the L1CrossDomainMessenger contract.
14
+ /// refer to https://docs.optimism.io/builders/dapp-developers/bridging/messaging#basics-of-communication-between-layers
15
+ /// @dev Recovery:
16
+ /// 1. If the message is not executed or failed to execute on the destination chain, you can manually retry by calling `relayMessage` on the `CrossDomainMessenger` contract.
17
+ /// refer to https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L211C14-L211C26
18
+ contract OptimismDVNAdapterL1 is DVNAdapterBase {
19
+ // --- Errors ---
20
+ error OnlyOptimism();
21
+ error NoPeer();
22
+
23
+ // --- Events ---
24
+ event PeerSet(address indexed peer);
25
+ event GasLimitSet(uint32 gasLimit);
26
+
27
+ uint32 public immutable optimismEid; // eid % 30000 (v1 eid)
28
+ address public immutable l1Messenger; // L1CrossDomainMessenger
29
+
30
+ uint32 public gasLimit;
31
+ address public peer;
32
+
33
+ constructor(
34
+ address[] memory _admins,
35
+ uint32 _optimismEid,
36
+ address _l1Messenger
37
+ ) DVNAdapterBase(msg.sender, _admins, 12000) {
38
+ optimismEid = _optimismEid; // eid % 30000 (v1 eid)
39
+ l1Messenger = _l1Messenger;
40
+ }
41
+
42
+ // --- Admin ---
43
+ function setGasLimit(uint32 _gasLimit) external onlyRole(ADMIN_ROLE) {
44
+ gasLimit = _gasLimit;
45
+ emit GasLimitSet(_gasLimit);
46
+ }
47
+
48
+ function setPeer(address _peer) external onlyRole(ADMIN_ROLE) {
49
+ peer = _peer;
50
+ emit PeerSet(_peer);
51
+ }
52
+
53
+ // --- Send ---
54
+ function assignJob(
55
+ AssignJobParam calldata _param,
56
+ bytes calldata /*_options*/
57
+ ) external payable override onlyAcl(_param.sender) returns (uint256) {
58
+ _getAndAssertReceiveLib(msg.sender, _param.dstEid);
59
+
60
+ if (_param.dstEid % 30000 != optimismEid) revert OnlyOptimism();
61
+ if (peer == address(0)) revert NoPeer();
62
+
63
+ bytes memory payload = abi.encodeWithSelector(
64
+ OptimismDVNAdapterL2.verify.selector,
65
+ DVNAdapterMessageCodec.encode(
66
+ receiveLibs[msg.sender][_param.dstEid],
67
+ _param.packetHeader,
68
+ _param.payloadHash
69
+ )
70
+ );
71
+ ICrossDomainMessenger(l1Messenger).sendMessage(peer, payload, gasLimit);
72
+
73
+ return 0;
74
+ }
75
+
76
+ // --- View ---
77
+ function getFee(
78
+ uint32 /*_dstEid*/,
79
+ uint64 /*_confirmations*/,
80
+ address _sender,
81
+ bytes calldata /*_options*/
82
+ ) public view override onlyAcl(_sender) returns (uint256) {
83
+ // no fee, charged as gas when sending message from L1 to L2
84
+ return 0;
85
+ }
86
+ }
@@ -0,0 +1,58 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol";
6
+
7
+ import { DVNAdapterBase } from "../DVNAdapterBase.sol";
8
+
9
+ contract OptimismDVNAdapterL2 is DVNAdapterBase {
10
+ // --- Errors ---
11
+ error UntrustedPeer(address peer);
12
+ error Unauthorized();
13
+
14
+ // --- Events ---
15
+ event PeerSet(address indexed peer);
16
+
17
+ address public immutable l2Messenger; // L2CrossDomainMessenger
18
+
19
+ address public peer;
20
+
21
+ constructor(address[] memory _admins, address _l2Messenger) DVNAdapterBase(msg.sender, _admins, 12000) {
22
+ l2Messenger = _l2Messenger;
23
+ }
24
+
25
+ // --- Admin ---
26
+ function setPeer(address _peer) external onlyRole(ADMIN_ROLE) {
27
+ peer = _peer;
28
+ emit PeerSet(_peer);
29
+ }
30
+
31
+ // --- Send ---
32
+ function assignJob(
33
+ AssignJobParam calldata /*_param*/,
34
+ bytes calldata /*_options*/
35
+ ) external payable override returns (uint256) {
36
+ revert DVNAdapter_NotImplemented();
37
+ }
38
+
39
+ function getFee(
40
+ uint32 /*_dstEid*/,
41
+ uint64 /*_confirmations*/,
42
+ address /*_sender*/,
43
+ bytes calldata /*_options*/
44
+ ) external pure override returns (uint256) {
45
+ revert DVNAdapter_NotImplemented();
46
+ }
47
+
48
+ // --- Receive ---
49
+ function verify(bytes calldata _payload) external {
50
+ // assert messenger
51
+ if (msg.sender != l2Messenger) revert Unauthorized();
52
+ // assert peer
53
+ address xSender = ICrossDomainMessenger(l2Messenger).xDomainMessageSender();
54
+ if (xSender != peer) revert UntrustedPeer(xSender);
55
+
56
+ _decodeAndVerify(0, _payload); //todo: fix
57
+ }
58
+ }
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >=0.8.0;
4
+
5
+ import { IWorker } from "../../interfaces/IWorker.sol";
6
+ import { ILayerZeroDVN } from "./ILayerZeroDVN.sol";
7
+ import { ILayerZeroReadDVN } from "./ILayerZeroReadDVN.sol";
8
+
9
+ interface IDVN is IWorker, ILayerZeroDVN, ILayerZeroReadDVN {
10
+ struct DstConfigParam {
11
+ uint32 dstEid;
12
+ uint64 gas;
13
+ uint16 multiplierBps;
14
+ uint128 floorMarginUSD;
15
+ }
16
+
17
+ struct DstConfig {
18
+ uint64 gas;
19
+ uint16 multiplierBps;
20
+ uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
21
+ }
22
+
23
+ event SetDstConfig(DstConfigParam[] params);
24
+
25
+ function dstConfig(uint32 _dstEid) external view returns (uint64, uint16, uint128);
26
+ }