@layerzerolabs/lz-evm-messagelib-v2 2.0.13 → 2.0.15
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/artifacts/contracts/Executor.sol/Executor.json +20 -20
- package/artifacts/contracts/ExecutorFeeLib.sol/ExecutorFeeLib.json +19 -19
- package/artifacts/contracts/MessageLibBase.sol/MessageLibBase.json +1 -1
- package/artifacts/contracts/PriceFeed.sol/PriceFeed.json +15 -15
- package/artifacts/contracts/ReceiveLibBaseE2.sol/ReceiveLibBaseE2.json +1 -1
- package/artifacts/contracts/SendLibBase.sol/SendLibBase.json +6 -6
- package/artifacts/contracts/SendLibBaseE2.sol/SendLibBaseE2.json +10 -10
- package/artifacts/contracts/Treasury.sol/Treasury.json +9 -9
- package/artifacts/contracts/Worker.sol/Worker.json +18 -18
- package/artifacts/contracts/interfaces/IExecutor.sol/IExecutor.json +3 -3
- package/artifacts/contracts/interfaces/IExecutorFeeLib.sol/IExecutorFeeLib.json +4 -4
- package/artifacts/contracts/interfaces/ILayerZeroPriceFeed.sol/ILayerZeroPriceFeed.json +3 -3
- package/artifacts/contracts/interfaces/IWorker.sol/IWorker.json +3 -3
- package/artifacts/contracts/uln/LzExecutor.sol/IReceiveUlnView.json +35 -0
- package/artifacts/contracts/uln/LzExecutor.sol/LzExecutor.json +279 -20
- package/artifacts/contracts/uln/ReceiveUlnBase.sol/ReceiveUlnBase.json +90 -11
- package/artifacts/contracts/uln/SendUlnBase.sol/SendUlnBase.json +7 -7
- package/artifacts/contracts/uln/UlnBase.sol/UlnBase.json +7 -7
- package/artifacts/contracts/uln/dvn/DVN.sol/DVN.json +31 -31
- package/artifacts/contracts/uln/dvn/DVNFeeLib.sol/DVNFeeLib.json +14 -14
- package/artifacts/contracts/uln/dvn/MultiSig.sol/MultiSig.json +5 -5
- package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol/CCIPDVNAdapter.json +488 -169
- package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol/CCIPDVNAdapterFeeLib.json +372 -16
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterBase.sol/DVNAdapterBase.json +419 -93
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterBase.sol/IReceiveUln.json +34 -0
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterBase.sol/ISendLibBase.json +30 -0
- package/artifacts/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL1.sol/ArbitrumDVNAdapterL1.json +936 -0
- package/artifacts/contracts/uln/dvn/adapters/arbitrum/ArbitrumDVNAdapterL2.sol/ArbitrumDVNAdapterL2.json +868 -0
- package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol/AxelarDVNAdapter.json +611 -249
- package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol/ISendLibBase.json +30 -0
- package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol/AxelarDVNAdapterFeeLib.json +526 -13
- package/artifacts/contracts/uln/dvn/adapters/libs/DVNAdapterMessageCodec.sol/DVNAdapterMessageCodec.json +16 -0
- package/artifacts/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL1.sol/OptimismDVNAdapterL1.json +924 -0
- package/artifacts/contracts/uln/dvn/adapters/optimism/OptimismDVNAdapterL2.sol/OptimismDVNAdapterL2.json +891 -0
- package/artifacts/contracts/uln/interfaces/IDVN.sol/IDVN.json +3 -3
- package/artifacts/contracts/uln/interfaces/IDVNFeeLib.sol/IDVNFeeLib.json +1 -1
- package/artifacts/contracts/uln/interfaces/IReceiveUlnE2.sol/IReceiveUlnE2.json +0 -24
- package/artifacts/contracts/uln/interfaces/adapters/IAxelarDVNAdapter.sol/IAxelarDVNAdapter.json +160 -0
- package/artifacts/contracts/uln/interfaces/adapters/IAxelarDVNAdapterFeeLib.sol/IAxelarDVNAdapterFeeLib.json +282 -0
- package/artifacts/contracts/uln/interfaces/adapters/ICCIPDVNAdapter.sol/ICCIPDVNAdapter.json +91 -0
- package/artifacts/contracts/uln/interfaces/adapters/ICCIPDVNAdapterFeeLib.sol/ICCIPDVNAdapterFeeLib.json +290 -0
- package/artifacts/contracts/uln/libs/DVNOptions.sol/DVNOptions.json +4 -4
- package/artifacts/contracts/uln/libs/UlnOptions.sol/UlnOptions.json +7 -7
- package/artifacts/contracts/uln/uln301/AddressSizeConfig.sol/AddressSizeConfig.json +2 -2
- package/artifacts/contracts/uln/uln301/ReceiveLibBaseE1.sol/ReceiveLibBaseE1.json +5 -5
- package/artifacts/contracts/uln/uln301/ReceiveUln301.sol/ReceiveUln301.json +88 -57
- package/artifacts/contracts/uln/uln301/ReceiveUln301View.sol/IReceiveUln301.json +178 -0
- package/artifacts/contracts/uln/uln301/ReceiveUln301View.sol/ReceiveUln301View.json +126 -0
- package/artifacts/contracts/uln/uln301/SendLibBaseE1.sol/SendLibBaseE1.json +15 -15
- package/artifacts/contracts/uln/uln301/SendUln301.sol/SendUln301.json +76 -76
- package/artifacts/contracts/uln/uln301/TreasuryFeeHandler.sol/TreasuryFeeHandler.json +5 -5
- package/artifacts/contracts/uln/uln301/interfaces/IMessageLibE1.sol/IMessageLibE1.json +4 -4
- package/artifacts/contracts/uln/uln302/ReceiveUln302.sol/ReceiveUln302.json +79 -24
- package/artifacts/contracts/uln/uln302/ReceiveUln302View.sol/IReceiveUln302.json +146 -0
- package/artifacts/contracts/uln/uln302/ReceiveUln302View.sol/ReceiveUln302View.json +251 -0
- package/artifacts/contracts/uln/uln302/SendUln302.sol/SendUln302.json +75 -75
- package/artifacts/contracts/upgradeable/WorkerUpgradeable.sol/WorkerUpgradeable.json +18 -18
- package/contracts/ExecutorFeeLib.sol +6 -6
- package/contracts/MessageLibBase.sol +2 -2
- package/contracts/PriceFeed.sol +3 -3
- package/contracts/ReceiveLibBaseE2.sol +0 -26
- package/contracts/SendLibBase.sol +10 -10
- package/contracts/SendLibBaseE2.sol +4 -4
- package/contracts/Treasury.sol +2 -2
- package/contracts/Worker.sol +3 -3
- package/contracts/interfaces/IExecutorFeeLib.sol +4 -4
- package/contracts/interfaces/ILayerZeroPriceFeed.sol +3 -3
- package/contracts/interfaces/IWorker.sol +3 -3
- package/contracts/uln/LzExecutor.sol +51 -19
- package/contracts/uln/ReceiveUlnBase.sol +21 -14
- package/contracts/uln/UlnBase.sol +19 -19
- package/contracts/uln/dvn/DVN.sol +16 -16
- package/contracts/uln/dvn/DVNFeeLib.sol +2 -2
- package/contracts/uln/dvn/MultiSig.sol +13 -13
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol +95 -97
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol +64 -2
- package/contracts/uln/dvn/adapters/DVNAdapterBase.sol +74 -124
- 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 +85 -100
- package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol +121 -2
- package/contracts/uln/dvn/adapters/libs/DVNAdapterMessageCodec.sol +36 -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/IDVNFeeLib.sol +1 -1
- package/contracts/uln/interfaces/IReceiveUlnE2.sol +0 -5
- package/contracts/uln/interfaces/adapters/IAxelarDVNAdapter.sol +45 -0
- package/contracts/uln/interfaces/adapters/IAxelarDVNAdapterFeeLib.sol +48 -0
- package/contracts/uln/interfaces/adapters/ICCIPDVNAdapter.sol +30 -0
- package/contracts/uln/interfaces/adapters/ICCIPDVNAdapterFeeLib.sol +45 -0
- package/contracts/uln/libs/DVNOptions.sol +6 -6
- package/contracts/uln/libs/UlnOptions.sol +13 -13
- package/contracts/uln/uln301/AddressSizeConfig.sol +4 -4
- package/contracts/uln/uln301/ReceiveLibBaseE1.sol +4 -4
- package/contracts/uln/uln301/ReceiveUln301.sol +4 -41
- package/contracts/uln/uln301/ReceiveUln301View.sol +89 -0
- package/contracts/uln/uln301/SendLibBaseE1.sol +5 -5
- package/contracts/uln/uln301/SendUln301.sol +3 -3
- package/contracts/uln/uln301/TreasuryFeeHandler.sol +6 -6
- package/contracts/uln/uln301/interfaces/IMessageLibE1.sol +4 -4
- package/contracts/uln/uln302/ReceiveUln302.sol +4 -27
- package/contracts/uln/uln302/ReceiveUln302View.sol +89 -0
- package/contracts/uln/uln302/SendUln302.sol +3 -3
- package/contracts/upgradeable/WorkerUpgradeable.sol +3 -3
- package/package.json +7 -5
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol/DVNAdapterFeeLibBase.json +0 -50
- package/artifacts/contracts/uln/interfaces/IDVNAdapterFeeLib.sol/IDVNAdapterFeeLib.json +0 -50
- package/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol +0 -20
- package/contracts/uln/interfaces/IDVNAdapterFeeLib.sol +0 -13
|
@@ -2,161 +2,111 @@
|
|
|
2
2
|
|
|
3
3
|
pragma solidity ^0.8.20;
|
|
4
4
|
|
|
5
|
-
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
|
6
|
-
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
|
|
7
|
-
|
|
8
5
|
import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
|
|
9
|
-
import { IMessageLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLib.sol";
|
|
10
6
|
import { ISendLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
11
7
|
|
|
12
8
|
import { ILayerZeroDVN } from "../../interfaces/ILayerZeroDVN.sol";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
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
|
+
}
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
struct ReceiveLibParam {
|
|
21
|
+
address sendLib;
|
|
22
|
+
uint32 dstEid;
|
|
23
|
+
bytes32 receiveLib;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// @title SendDVNAdapterBase
|
|
17
27
|
/// @notice base contract for DVN adapters
|
|
18
28
|
/// @dev limitations:
|
|
19
29
|
/// - doesn't accept alt token
|
|
20
30
|
/// - doesn't respect block confirmations
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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);
|
|
24
36
|
|
|
25
|
-
|
|
26
|
-
uint32 dstEid;
|
|
27
|
-
uint16 multiplierBps;
|
|
28
|
-
}
|
|
37
|
+
event ReceiveLibsSet(ReceiveLibParam[] params);
|
|
29
38
|
|
|
30
|
-
/// @dev
|
|
31
|
-
///
|
|
32
|
-
/// in the receive library due to insufficient confirmations if the config was changed before the message is received
|
|
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
|
|
33
41
|
uint64 internal constant MAX_CONFIRMATIONS = type(uint64).max;
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
event AdminSet(address indexed admin, bool isAdmin);
|
|
52
|
-
event DefaultMultiplierSet(uint16 multiplierBps);
|
|
53
|
-
event DstMultiplierSet(DstMultiplierParam[] params);
|
|
54
|
-
event FeeLibSet(address indexed feeLib);
|
|
55
|
-
event FeeWithdrawn(address indexed to, uint256 amount);
|
|
56
|
-
event TokenWithdrawn(address indexed to, address token, uint256 amount);
|
|
57
|
-
|
|
58
|
-
modifier onlySendLib() {
|
|
59
|
-
if (msg.sender != address(sendLib)) revert OnlySendLib();
|
|
60
|
-
_;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
modifier onlyAdmin() {
|
|
64
|
-
if (!admins[msg.sender]) revert Unauthorized();
|
|
65
|
-
_;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
constructor(address _sendLib, address _receiveLib, address[] memory _admins) {
|
|
69
|
-
(uint64 sendMajor, uint8 sendMinor, uint8 sendEndpoint) = IMessageLib(_sendLib).version();
|
|
70
|
-
(uint64 receiveMajor, uint8 receiveMinor, uint8 receiveEndpoint) = IMessageLib(_receiveLib).version();
|
|
71
|
-
|
|
72
|
-
if (sendMajor != receiveMajor || sendMinor != receiveMinor || sendEndpoint != receiveEndpoint) {
|
|
73
|
-
revert VersionMismatch();
|
|
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;
|
|
74
59
|
}
|
|
75
60
|
|
|
76
|
-
|
|
77
|
-
receiveLib = IReceiveUlnE2(_receiveLib);
|
|
78
|
-
|
|
79
|
-
for (uint256 i = 0; i < _admins.length; i++) {
|
|
80
|
-
admins[_admins[i]] = true;
|
|
81
|
-
emit AdminSet(_admins[i], true);
|
|
82
|
-
}
|
|
61
|
+
emit ReceiveLibsSet(_params);
|
|
83
62
|
}
|
|
84
63
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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);
|
|
88
68
|
}
|
|
89
69
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
emit DefaultMultiplierSet(_defaultMultiplierBps);
|
|
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);
|
|
97
76
|
}
|
|
98
77
|
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
function _encodeEmpty() internal pure returns (bytes memory) {
|
|
79
|
+
return
|
|
80
|
+
DVNAdapterMessageCodec.encode(bytes32(0), new bytes(DVNAdapterMessageCodec.PACKET_HEADER_SIZE), bytes32(0));
|
|
102
81
|
}
|
|
103
82
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
/// @param _amount amount to withdraw
|
|
107
|
-
function withdrawFee(address _to, uint256 _amount) external onlyAdmin {
|
|
108
|
-
_withdrawFee(_to, _amount);
|
|
109
|
-
}
|
|
83
|
+
function _decodeAndVerify(bytes calldata _payload) internal {
|
|
84
|
+
(address receiveLib, bytes memory packetHeader, bytes32 payloadHash) = DVNAdapterMessageCodec.decode(_payload);
|
|
110
85
|
|
|
111
|
-
|
|
112
|
-
/// @param _token token address
|
|
113
|
-
/// @param _to address to withdraw token to
|
|
114
|
-
/// @param _amount amount to withdraw
|
|
115
|
-
function withdrawToken(address _token, address _to, uint256 _amount) external onlyAdmin {
|
|
116
|
-
// transfers native if _token is address(0x0)
|
|
117
|
-
Transfer.nativeOrToken(_token, _to, _amount);
|
|
118
|
-
emit TokenWithdrawn(_to, _token, _amount);
|
|
86
|
+
IReceiveUln(receiveLib).verify(packetHeader, payloadHash, MAX_CONFIRMATIONS);
|
|
119
87
|
}
|
|
120
88
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (balance < _messageFee) {
|
|
127
|
-
// withdraw fees from the sendLib if balance is insufficient
|
|
128
|
-
// sendLib will revert if not enough fees were accumulated
|
|
129
|
-
_withdrawFee(address(this), _messageFee - balance); // todo: why not withdraw all fees from sendLib? so that dont need to withdraw every time
|
|
89
|
+
function _withdrawFeeFromSendLib(address _sendLib, address _to) internal {
|
|
90
|
+
uint256 fee = ISendLibBase(_sendLib).fees(address(this));
|
|
91
|
+
if (fee > 0) {
|
|
92
|
+
ISendLib(_sendLib).withdrawFee(_to, fee);
|
|
93
|
+
emit Withdraw(_sendLib, _to, fee);
|
|
130
94
|
}
|
|
131
95
|
}
|
|
132
96
|
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
function _encodePayload(
|
|
139
|
-
bytes memory _packetHeader,
|
|
140
|
-
bytes32 _payloadHash
|
|
141
|
-
) internal pure returns (bytes memory payload) {
|
|
142
|
-
return abi.encodePacked(_packetHeader, _payloadHash);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function _decodePayload(
|
|
146
|
-
bytes memory _payload
|
|
147
|
-
) internal pure returns (bytes memory packetHeader, bytes32 payloadHash) {
|
|
148
|
-
if (_payload.length != PAYLOAD_SIZE) revert InvalidPayloadSize();
|
|
149
|
-
uint256 start = 0;
|
|
150
|
-
packetHeader = _payload.slice(start, PACKET_HEADER_SIZE);
|
|
151
|
-
|
|
152
|
-
start += PACKET_HEADER_SIZE;
|
|
153
|
-
payloadHash = _payload.toBytes32(start);
|
|
154
|
-
}
|
|
97
|
+
function _assertBalanceAndWithdrawFee(address _sendLib, uint256 _messageFee) internal {
|
|
98
|
+
uint256 balance = address(this).balance;
|
|
99
|
+
if (balance < _messageFee) {
|
|
100
|
+
// withdraw all fees from the sendLib if balance is insufficient
|
|
101
|
+
_withdrawFeeFromSendLib(_sendLib, address(this));
|
|
155
102
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
103
|
+
// check balance again
|
|
104
|
+
balance = address(this).balance;
|
|
105
|
+
// revert if balance is still insufficient, need to transfer more funds manually to the adapter
|
|
106
|
+
if (balance < _messageFee) revert DVNAdapter_InsufficientBalance(balance, _messageFee);
|
|
107
|
+
}
|
|
159
108
|
}
|
|
160
109
|
|
|
110
|
+
/// @dev to receive refund
|
|
161
111
|
receive() external payable {}
|
|
162
112
|
}
|
|
@@ -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(_payload);
|
|
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
|
|
@@ -3,154 +3,139 @@
|
|
|
3
3
|
pragma solidity ^0.8.20;
|
|
4
4
|
|
|
5
5
|
import { AxelarExecutable } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
|
|
6
|
-
import {
|
|
6
|
+
import { ISendLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
7
7
|
|
|
8
8
|
import { DVNAdapterBase } from "../DVNAdapterBase.sol";
|
|
9
|
+
import { IAxelarDVNAdapter } from "../../../interfaces/adapters/IAxelarDVNAdapter.sol";
|
|
10
|
+
import { IAxelarDVNAdapterFeeLib } from "../../../interfaces/adapters/IAxelarDVNAdapterFeeLib.sol";
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
uint16 multiplierBps;
|
|
14
|
-
uint256 nativeGasFee;
|
|
15
|
-
string peer;
|
|
16
|
-
string chainName;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
struct DstFeeParam {
|
|
20
|
-
uint32 dstEid;
|
|
21
|
-
uint256 nativeGasFee;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct DstConfig {
|
|
25
|
-
uint256 nativeGasFee;
|
|
26
|
-
uint16 multiplierBps;
|
|
27
|
-
string peer;
|
|
28
|
-
string chainName;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
event DstConfigSet(DstConfigParam[] params);
|
|
32
|
-
event DstFeeSet(DstFeeParam[] params);
|
|
33
|
-
|
|
34
|
-
IAxelarGasService public immutable gasService;
|
|
35
|
-
|
|
36
|
-
mapping(uint32 dstEid => DstConfig config) public dstConfig;
|
|
37
|
-
mapping(string axelarChain => uint32 eid) public axelarChainToEid;
|
|
12
|
+
interface ISendLibBase {
|
|
13
|
+
function fees(address _worker) external view returns (uint256);
|
|
14
|
+
}
|
|
38
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 axelarChain => string peer) public peers; // by chain name
|
|
34
|
+
mapping(uint32 dstEid => DstConfig) public dstConfig; // by dstEid
|
|
35
|
+
|
|
36
|
+
// set default multiplier to 2.5x
|
|
39
37
|
constructor(
|
|
40
|
-
address _sendLib,
|
|
41
|
-
address _receiveLib,
|
|
42
38
|
address[] memory _admins,
|
|
43
|
-
address _gateway
|
|
44
|
-
|
|
45
|
-
) AxelarExecutable(_gateway) DVNAdapterBase(_sendLib, _receiveLib, _admins) {
|
|
46
|
-
gasService = IAxelarGasService(_gasReceiver);
|
|
47
|
-
}
|
|
39
|
+
address _gateway
|
|
40
|
+
) AxelarExecutable(_gateway) DVNAdapterBase(msg.sender, _admins, 12000) {}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/// @param _params array of chain configurations
|
|
52
|
-
function setDstConfig(DstConfigParam[] calldata _params) external onlyAdmin {
|
|
42
|
+
// ========================= OnlyAdmin =========================
|
|
43
|
+
function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
|
|
53
44
|
for (uint256 i = 0; i < _params.length; i++) {
|
|
54
45
|
DstConfigParam calldata param = _params[i];
|
|
55
46
|
|
|
56
|
-
delete
|
|
47
|
+
delete peers[dstConfig[param.dstEid].chainName]; // delete old peer in case chain name by dstEid is updated
|
|
48
|
+
peers[param.chainName] = param.peer; // update peer
|
|
57
49
|
|
|
58
|
-
|
|
59
|
-
dstConfig[param.dstEid] = DstConfig({
|
|
60
|
-
nativeGasFee: param.nativeGasFee,
|
|
61
|
-
multiplierBps: param.multiplierBps,
|
|
62
|
-
peer: param.peer,
|
|
63
|
-
chainName: param.chainName
|
|
64
|
-
});
|
|
50
|
+
dstConfig[param.dstEid] = DstConfig(param.chainName, param.peer, param.multiplierBps, param.nativeGasFee); // update config by dstEid
|
|
65
51
|
}
|
|
66
52
|
|
|
67
53
|
emit DstConfigSet(_params);
|
|
68
54
|
}
|
|
69
55
|
|
|
70
56
|
/// @notice sets message fee in native gas for destination chains.
|
|
71
|
-
/// @dev Axelar does not support quoting fee
|
|
57
|
+
/// @dev Axelar does not support quoting fee on-chain. Instead, the fee needs to be obtained off-chain by querying through the Axelar SDK.
|
|
72
58
|
/// @dev The fee may change over time when token prices change, requiring admins to monitor and make necessary updates to reflect the actual fee.
|
|
73
59
|
/// @dev Adding a buffer to the required fee is advisable. Any surplus fee will be refunded asynchronously if it exceeds the necessary amount.
|
|
74
60
|
/// https://docs.axelar.dev/dev/general-message-passing/gas-services/pay-gas
|
|
75
61
|
/// https://github.com/axelarnetwork/axelarjs/blob/070c8fe061f1082e79772fdc5c4675c0237bbba2/packages/api/src/axelar-query/isomorphic.ts#L54
|
|
76
62
|
/// https://github.com/axelarnetwork/axelar-cgp-solidity/blob/d4536599321774927bf9716178a9e360f8e0efac/contracts/gas-service/AxelarGasService.sol#L403
|
|
77
|
-
|
|
78
|
-
function setDstNativeGasFee(DstFeeParam[] calldata _params) external onlyAdmin {
|
|
79
|
-
// TODO - can delete and call setDstConfig instead?
|
|
63
|
+
function setNativeGasFee(NativeGasFeeParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
|
|
80
64
|
for (uint256 i = 0; i < _params.length; i++) {
|
|
81
|
-
|
|
65
|
+
NativeGasFeeParam calldata param = _params[i];
|
|
82
66
|
dstConfig[param.dstEid].nativeGasFee = param.nativeGasFee;
|
|
83
67
|
}
|
|
84
|
-
|
|
85
|
-
emit DstFeeSet(_params);
|
|
68
|
+
emit NativeGasFeeSet(_params);
|
|
86
69
|
}
|
|
87
70
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// TODO - can delete and call setDstConfig instead?
|
|
92
|
-
for (uint256 i = 0; i < _params.length; i++) {
|
|
93
|
-
DstMultiplierParam calldata param = _params[i];
|
|
94
|
-
dstConfig[param.dstEid].multiplierBps = param.multiplierBps;
|
|
95
|
-
}
|
|
71
|
+
// ========================= OnlyWorkerFeeLib =========================
|
|
72
|
+
function withdrawToFeeLib(address _sendLib) external {
|
|
73
|
+
if (msg.sender != workerFeeLib) revert AxelarDVNAdapter_OnlyWorkerFeeLib();
|
|
96
74
|
|
|
97
|
-
|
|
75
|
+
_withdrawFeeFromSendLib(_sendLib, workerFeeLib);
|
|
98
76
|
}
|
|
99
77
|
|
|
78
|
+
// ========================= OnlyMessageLib =========================
|
|
100
79
|
function assignJob(
|
|
101
80
|
AssignJobParam calldata _param,
|
|
102
|
-
bytes calldata
|
|
103
|
-
) external payable override
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
81
|
+
bytes calldata _options
|
|
82
|
+
) external payable override onlyAcl(_param.sender) returns (uint totalFee) {
|
|
83
|
+
bytes32 receiveLib = _getAndAssertReceiveLib(msg.sender, _param.dstEid);
|
|
84
|
+
|
|
85
|
+
IAxelarDVNAdapterFeeLib.Param memory feeLibParam = IAxelarDVNAdapterFeeLib.Param({
|
|
86
|
+
dstEid: _param.dstEid,
|
|
87
|
+
confirmations: _param.confirmations,
|
|
88
|
+
sender: _param.sender,
|
|
89
|
+
defaultMultiplierBps: defaultMultiplierBps
|
|
90
|
+
});
|
|
91
|
+
DstConfig memory config = dstConfig[_param.dstEid];
|
|
92
|
+
|
|
93
|
+
bytes memory payload = _encode(receiveLib, _param.packetHeader, _param.payloadHash);
|
|
94
|
+
|
|
95
|
+
totalFee = IAxelarDVNAdapterFeeLib(workerFeeLib).getFeeOnSend(
|
|
96
|
+
feeLibParam,
|
|
97
|
+
config,
|
|
98
|
+
payload,
|
|
99
|
+
_options,
|
|
100
|
+
msg.sender
|
|
119
101
|
);
|
|
120
|
-
// https://docs.axelar.dev/dev/general-message-passing/gmp-messages#call-a-contract-on-chain-b-from-chain-a
|
|
121
|
-
gateway.callContract(dstChainName, dstPeer, payload);
|
|
122
102
|
|
|
123
|
-
|
|
124
|
-
fee = feeLib.getFee(_param.dstEid, _param.sender, defaultMultiplierBps, config.multiplierBps, fee);
|
|
125
|
-
}
|
|
103
|
+
gateway.callContract(config.chainName, config.peer, payload);
|
|
126
104
|
}
|
|
127
105
|
|
|
106
|
+
// ========================= View =========================
|
|
128
107
|
function getFee(
|
|
129
108
|
uint32 _dstEid,
|
|
130
|
-
uint64
|
|
109
|
+
uint64 _confirmations,
|
|
131
110
|
address _sender,
|
|
132
|
-
bytes calldata
|
|
133
|
-
) external view override returns (uint256
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
111
|
+
bytes calldata _options
|
|
112
|
+
) external view override returns (uint256 totalFee) {
|
|
113
|
+
IAxelarDVNAdapterFeeLib.Param memory feeLibParam = IAxelarDVNAdapterFeeLib.Param(
|
|
114
|
+
_dstEid,
|
|
115
|
+
_confirmations,
|
|
116
|
+
_sender,
|
|
117
|
+
defaultMultiplierBps
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
totalFee = IAxelarDVNAdapterFeeLib(workerFeeLib).getFee(feeLibParam, dstConfig[_dstEid], _options);
|
|
139
121
|
}
|
|
140
122
|
|
|
123
|
+
// ========================= Internal =========================
|
|
141
124
|
function _execute(
|
|
142
125
|
string calldata _sourceChain,
|
|
143
126
|
string calldata _sourceAddress,
|
|
144
127
|
bytes calldata _payload
|
|
145
128
|
) internal override {
|
|
129
|
+
// assert peer is the same as the source chain
|
|
146
130
|
_assertPeer(_sourceChain, _sourceAddress);
|
|
147
|
-
_verify(_payload);
|
|
148
|
-
}
|
|
149
131
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
string memory sourcePeer = dstConfig[sourceEid].peer;
|
|
132
|
+
_decodeAndVerify(_payload);
|
|
133
|
+
}
|
|
153
134
|
|
|
154
|
-
|
|
135
|
+
function _assertPeer(string memory _sourceChain, string memory _sourceAddress) private view {
|
|
136
|
+
string memory sourcePeer = peers[_sourceChain];
|
|
137
|
+
if (keccak256(bytes(_sourceAddress)) != keccak256(bytes(sourcePeer))) {
|
|
138
|
+
revert AxelarDVNAdapter_UntrustedPeer(_sourceChain, _sourceAddress);
|
|
139
|
+
}
|
|
155
140
|
}
|
|
156
141
|
}
|