@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.
- package/README.md +15 -0
- package/contracts/Executor.sol +339 -0
- package/contracts/ExecutorFeeLib.sol +241 -0
- package/contracts/MessageLibBase.sol +21 -0
- package/contracts/PriceFeed.sol +304 -0
- package/contracts/ReceiveLibBaseE2.sol +28 -0
- package/contracts/SendLibBase.sol +258 -0
- package/contracts/SendLibBaseE2.sol +140 -0
- package/contracts/SimpleReadExecutor.sol +110 -0
- package/contracts/Treasury.sol +74 -0
- package/contracts/Worker.sol +167 -0
- package/contracts/decompressor/DVNDecoder.sol +52 -0
- package/contracts/decompressor/DVNDecompressor.sol +70 -0
- package/contracts/decompressor/DecompressorExtension.sol +204 -0
- package/contracts/decompressor/ExecutorDecoder.sol +147 -0
- package/contracts/decompressor/ExecutorDecompressor.sol +58 -0
- package/contracts/interfaces/IExecutor.sol +47 -0
- package/contracts/interfaces/IExecutorFeeLib.sol +56 -0
- package/contracts/interfaces/ILayerZeroExecutor.sol +29 -0
- package/contracts/interfaces/ILayerZeroPriceFeed.sol +61 -0
- package/contracts/interfaces/ILayerZeroReadExecutor.sol +15 -0
- package/contracts/interfaces/ILayerZeroTreasury.sol +19 -0
- package/contracts/interfaces/IWorker.sol +29 -0
- package/contracts/libs/ExecutorOptions.sol +104 -0
- package/contracts/libs/SafeCall.sol +123 -0
- package/contracts/lowlat/EssenceDVNWrapper.sol +77 -0
- package/contracts/lowlat/MultiCall.sol +42 -0
- package/contracts/mocks/DVNMock.sol +28 -0
- package/contracts/mocks/ExecutorMock.sol +95 -0
- package/contracts/uln/LzExecutor.sol +129 -0
- package/contracts/uln/ReceiveUlnBase.sol +125 -0
- package/contracts/uln/SendUlnBase.sol +129 -0
- package/contracts/uln/UlnBase.sol +195 -0
- package/contracts/uln/dvn/DVN.sol +393 -0
- package/contracts/uln/dvn/DVNFeeLib.sol +288 -0
- package/contracts/uln/dvn/DeadDVN.sol +30 -0
- package/contracts/uln/dvn/MultiSig.sol +135 -0
- package/contracts/uln/dvn/SimpleReadDVN.sol +112 -0
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol +151 -0
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol +71 -0
- package/contracts/uln/dvn/adapters/DVNAdapterBase.sol +114 -0
- package/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL1.sol +126 -0
- package/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL2.sol +50 -0
- package/contracts/uln/dvn/adapters/avalanche/NOTES.md +4 -0
- package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol +152 -0
- package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol +127 -0
- package/contracts/uln/dvn/adapters/libs/DVNAdapterMessageCodec.sol +41 -0
- package/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL1.sol +86 -0
- package/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL2.sol +58 -0
- package/contracts/uln/interfaces/IDVN.sol +26 -0
- package/contracts/uln/interfaces/IDVNFeeLib.sol +56 -0
- package/contracts/uln/interfaces/ILayerZeroDVN.sol +34 -0
- package/contracts/uln/interfaces/ILayerZeroReadDVN.sol +27 -0
- package/contracts/uln/interfaces/IReceiveUlnE2.sol +13 -0
- package/contracts/uln/interfaces/adapters/IAxelarDVNAdapter.sol +50 -0
- package/contracts/uln/interfaces/adapters/IAxelarDVNAdapterFeeLib.sol +49 -0
- package/contracts/uln/interfaces/adapters/ICCIPDVNAdapter.sol +34 -0
- package/contracts/uln/interfaces/adapters/ICCIPDVNAdapterFeeLib.sol +46 -0
- package/contracts/uln/libs/DVNOptions.sol +181 -0
- package/contracts/uln/libs/ReadCmdCodecV1.sol +136 -0
- package/contracts/uln/libs/SupportedCmdTypes.sol +29 -0
- package/contracts/uln/libs/UlnOptions.sol +176 -0
- package/contracts/uln/readlib/ReadLib1002.sol +518 -0
- package/contracts/uln/readlib/ReadLib1002View.sol +98 -0
- package/contracts/uln/readlib/ReadLibBase.sol +187 -0
- package/contracts/uln/uln301/AddressSizeConfig.sol +22 -0
- package/contracts/uln/uln301/ReceiveLibBaseE1.sol +103 -0
- package/contracts/uln/uln301/ReceiveUln301.sol +83 -0
- package/contracts/uln/uln301/ReceiveUln301View.sol +89 -0
- package/contracts/uln/uln301/SendLibBaseE1.sol +194 -0
- package/contracts/uln/uln301/SendUln301.sol +99 -0
- package/contracts/uln/uln301/TreasuryFeeHandler.sol +41 -0
- package/contracts/uln/uln301/interfaces/IMessageLibE1.sol +22 -0
- package/contracts/uln/uln301/interfaces/INonceContract.sol +7 -0
- package/contracts/uln/uln301/interfaces/ITreasuryFeeHandler.sol +13 -0
- package/contracts/uln/uln301/interfaces/IUltraLightNode301.sol +7 -0
- package/contracts/uln/uln301/mocks/NonceContractMock.sol +23 -0
- package/contracts/uln/uln302/ReceiveUln302.sol +85 -0
- package/contracts/uln/uln302/ReceiveUln302View.sol +89 -0
- package/contracts/uln/uln302/SendUln302.sol +86 -0
- package/contracts/upgradeable/WorkerUpgradeable.sol +186 -0
- package/contracts/upgradeable/proxy/ProxyAdmin.sol +96 -0
- package/contracts/upgradeable/proxy/TransparentUpgradeableProxy.sol +131 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- 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
|
+
}
|