@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,194 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
6
|
+
import { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
|
|
7
|
+
import { GUID } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/GUID.sol";
|
|
8
|
+
import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
|
|
9
|
+
|
|
10
|
+
import { IMessageLibE1 } from "./interfaces/IMessageLibE1.sol";
|
|
11
|
+
import { ITreasuryFeeHandler } from "./interfaces/ITreasuryFeeHandler.sol";
|
|
12
|
+
import { INonceContract } from "./interfaces/INonceContract.sol";
|
|
13
|
+
import { SendLibBase, WorkerOptions, ExecutorConfig } from "../../SendLibBase.sol";
|
|
14
|
+
import { AddressSizeConfig } from "./AddressSizeConfig.sol";
|
|
15
|
+
|
|
16
|
+
/// @dev send-side message library base contract on endpoint v1.
|
|
17
|
+
/// design:
|
|
18
|
+
/// 1/ it enforces the path definition on V1 and interacts with the nonce contract
|
|
19
|
+
/// 2/ quote: first executor, then verifier (e.g. DVNs), then treasury
|
|
20
|
+
/// 3/ send: first executor, then verifier (e.g. DVNs), then treasury. the treasury pay much be DoS-proof
|
|
21
|
+
abstract contract SendLibBaseE1 is SendLibBase, AddressSizeConfig, IMessageLibE1 {
|
|
22
|
+
INonceContract public immutable nonceContract;
|
|
23
|
+
ITreasuryFeeHandler public immutable treasuryFeeHandler;
|
|
24
|
+
|
|
25
|
+
// config
|
|
26
|
+
address internal lzToken;
|
|
27
|
+
|
|
28
|
+
// this event should be identical to the one on Endpoint V2
|
|
29
|
+
event PacketSent(bytes encodedPayload, bytes options, uint256 nativeFee, uint256 lzTokenFee);
|
|
30
|
+
event NativeFeeWithdrawn(address user, address receiver, uint256 amount);
|
|
31
|
+
event LzTokenSet(address token);
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
address _endpoint,
|
|
35
|
+
uint256 _treasuryGasLimit,
|
|
36
|
+
uint256 _treasuryNativeFeeCap,
|
|
37
|
+
address _nonceContract,
|
|
38
|
+
uint32 _localEid,
|
|
39
|
+
address _treasuryFeeHandler
|
|
40
|
+
) SendLibBase(_endpoint, _localEid, _treasuryGasLimit, _treasuryNativeFeeCap) {
|
|
41
|
+
nonceContract = INonceContract(_nonceContract);
|
|
42
|
+
treasuryFeeHandler = ITreasuryFeeHandler(_treasuryFeeHandler);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ======================= OnlyEndpoint =======================
|
|
46
|
+
/// @dev the abstract process for send() is:
|
|
47
|
+
/// 1/ pay workers, which includes the executor and the validation workers
|
|
48
|
+
/// 2/ pay treasury
|
|
49
|
+
/// 3/ in EndpointV1, here we handle the fees and refunds
|
|
50
|
+
function send(
|
|
51
|
+
address _sender,
|
|
52
|
+
uint64, // _nonce
|
|
53
|
+
uint16 _dstEid,
|
|
54
|
+
bytes calldata _path, // remoteAddress + localAddress
|
|
55
|
+
bytes calldata _message,
|
|
56
|
+
address payable _refundAddress,
|
|
57
|
+
address _lzTokenPaymentAddress,
|
|
58
|
+
bytes calldata _options
|
|
59
|
+
) external payable onlyEndpoint {
|
|
60
|
+
(bytes memory encodedPacket, uint256 totalNativeFee) = _payWorkers(_sender, _dstEid, _path, _message, _options);
|
|
61
|
+
|
|
62
|
+
// quote treasury fee
|
|
63
|
+
uint32 dstEid = _dstEid; // stack too deep
|
|
64
|
+
address sender = _sender; // stack too deep
|
|
65
|
+
bool payInLzToken = _lzTokenPaymentAddress != address(0x0) && address(lzToken) != address(0x0);
|
|
66
|
+
(uint256 treasuryNativeFee, uint256 lzTokenFee) = _payTreasury(sender, dstEid, totalNativeFee, payInLzToken);
|
|
67
|
+
totalNativeFee += treasuryNativeFee;
|
|
68
|
+
|
|
69
|
+
// pay native fee
|
|
70
|
+
// assert the user has attached enough native token for this address
|
|
71
|
+
if (msg.value < totalNativeFee) revert LZ_MessageLib_InsufficientMsgValue();
|
|
72
|
+
// refund if they send too much
|
|
73
|
+
uint256 refundAmt = msg.value - totalNativeFee;
|
|
74
|
+
if (refundAmt > 0) {
|
|
75
|
+
Transfer.native(_refundAddress, refundAmt);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// pay lz token fee if needed
|
|
79
|
+
if (lzTokenFee > 0) {
|
|
80
|
+
// in v2, we let user pass a payInLzToken boolean but always charging the sender
|
|
81
|
+
// likewise in v1, if _lzTokenPaymentAddress is passed, it must be the sender
|
|
82
|
+
if (_lzTokenPaymentAddress != sender) revert LZ_MessageLib_LzTokenPaymentAddressMustBeSender();
|
|
83
|
+
_payLzTokenFee(sender, lzTokenFee);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
emit PacketSent(encodedPacket, _options, totalNativeFee, lzTokenFee);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ======================= OnlyOwner =======================
|
|
90
|
+
function setLzToken(address _lzToken) external onlyOwner {
|
|
91
|
+
lzToken = _lzToken;
|
|
92
|
+
emit LzTokenSet(_lzToken);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function setTreasury(address _treasury) external onlyOwner {
|
|
96
|
+
_setTreasury(_treasury);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ======================= External =======================
|
|
100
|
+
function withdrawFee(address _to, uint256 _amount) external {
|
|
101
|
+
_debitFee(_amount);
|
|
102
|
+
Transfer.native(_to, _amount);
|
|
103
|
+
emit NativeFeeWithdrawn(msg.sender, _to, _amount);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ======================= View =======================
|
|
107
|
+
function estimateFees(
|
|
108
|
+
uint16 _dstEid,
|
|
109
|
+
address _sender,
|
|
110
|
+
bytes calldata _message,
|
|
111
|
+
bool _payInLzToken,
|
|
112
|
+
bytes calldata _options
|
|
113
|
+
) external view returns (uint256 nativeFee, uint256 lzTokenFee) {
|
|
114
|
+
return _quote(_sender, _dstEid, _message.length, _payInLzToken, _options);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ======================= Internal =======================
|
|
118
|
+
/// @dev path = remoteAddress + localAddress.
|
|
119
|
+
function _assertPath(address _sender, bytes calldata _path, uint256 remoteAddressSize) internal pure {
|
|
120
|
+
if (_path.length != 20 + remoteAddressSize) revert LZ_MessageLib_InvalidPath();
|
|
121
|
+
address srcInPath = AddressCast.toAddress(_path[remoteAddressSize:]);
|
|
122
|
+
if (_sender != srcInPath) revert LZ_MessageLib_InvalidSender();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function _payLzTokenFee(address _sender, uint256 _lzTokenFee) internal {
|
|
126
|
+
treasuryFeeHandler.payFee(
|
|
127
|
+
lzToken,
|
|
128
|
+
_sender,
|
|
129
|
+
_lzTokenFee, // the supplied fee is always equal to the required fee
|
|
130
|
+
_lzTokenFee,
|
|
131
|
+
treasury
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/// @dev outbound does three things
|
|
136
|
+
/// @dev 1) asserts path
|
|
137
|
+
/// @dev 2) increments the nonce
|
|
138
|
+
/// @dev 3) assemble packet
|
|
139
|
+
/// @return packet to be sent to workers
|
|
140
|
+
function _outbound(
|
|
141
|
+
address _sender,
|
|
142
|
+
uint16 _dstEid,
|
|
143
|
+
bytes calldata _path,
|
|
144
|
+
bytes calldata _message
|
|
145
|
+
) internal returns (Packet memory packet) {
|
|
146
|
+
// assert toAddress size
|
|
147
|
+
uint256 remoteAddressSize = addressSizes[_dstEid];
|
|
148
|
+
if (remoteAddressSize == 0) revert LZ_MessageLib_InvalidPath();
|
|
149
|
+
_assertPath(_sender, _path, remoteAddressSize);
|
|
150
|
+
|
|
151
|
+
// increment nonce
|
|
152
|
+
uint64 nonce = nonceContract.increment(_dstEid, _sender, _path);
|
|
153
|
+
|
|
154
|
+
bytes32 receiver = AddressCast.toBytes32(_path[0:remoteAddressSize]);
|
|
155
|
+
|
|
156
|
+
bytes32 guid = GUID.generate(nonce, localEid, _sender, _dstEid, receiver);
|
|
157
|
+
|
|
158
|
+
// assemble packet
|
|
159
|
+
packet = Packet(nonce, localEid, _sender, _dstEid, receiver, guid, _message);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// 1/ handle executor
|
|
163
|
+
/// 2/ handle other workers
|
|
164
|
+
function _payWorkers(
|
|
165
|
+
address _sender,
|
|
166
|
+
uint16 _dstEid,
|
|
167
|
+
bytes calldata _path,
|
|
168
|
+
bytes calldata _message,
|
|
169
|
+
bytes calldata _options
|
|
170
|
+
) internal returns (bytes memory encodedPacket, uint256 totalNativeFee) {
|
|
171
|
+
Packet memory packet = _outbound(_sender, _dstEid, _path, _message);
|
|
172
|
+
|
|
173
|
+
// split workers options
|
|
174
|
+
(bytes memory executorOptions, WorkerOptions[] memory verificationOptions) = _splitOptions(_options);
|
|
175
|
+
|
|
176
|
+
// handle executor
|
|
177
|
+
ExecutorConfig memory config = getExecutorConfig(_sender, _dstEid);
|
|
178
|
+
uint256 msgSize = packet.message.length;
|
|
179
|
+
_assertMessageSize(msgSize, config.maxMessageSize);
|
|
180
|
+
totalNativeFee += _payExecutor(config.executor, packet.dstEid, packet.sender, msgSize, executorOptions);
|
|
181
|
+
|
|
182
|
+
// handle other workers
|
|
183
|
+
(uint256 verifierFee, bytes memory packetBytes) = _payVerifier(packet, verificationOptions);
|
|
184
|
+
totalNativeFee += verifierFee;
|
|
185
|
+
|
|
186
|
+
encodedPacket = packetBytes;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ======================= Virtual =======================
|
|
190
|
+
function _payVerifier(
|
|
191
|
+
Packet memory _packet, // packet is assembled in memory for endpoint-v1. so the location can not be calldata
|
|
192
|
+
WorkerOptions[] memory _options
|
|
193
|
+
) internal virtual returns (uint256 otherWorkerFees, bytes memory encodedPacket);
|
|
194
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
6
|
+
|
|
7
|
+
import { ExecutorConfig, WorkerOptions } from "../../SendLibBase.sol";
|
|
8
|
+
import { SendLibBaseE1 } from "./SendLibBaseE1.sol";
|
|
9
|
+
import { SendUlnBase } from "../SendUlnBase.sol";
|
|
10
|
+
import { UlnConfig } from "../UlnBase.sol";
|
|
11
|
+
|
|
12
|
+
/// @dev ULN301 will be deployed on EndpointV1 and is for backward compatibility with ULN302 on EndpointV2. 301 can talk to both 301 and 302
|
|
13
|
+
/// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
|
|
14
|
+
/// @dev In this case, it combines the logic of SendUlnBase and SendLibBaseE1
|
|
15
|
+
contract SendUln301 is SendUlnBase, SendLibBaseE1 {
|
|
16
|
+
uint256 internal constant CONFIG_TYPE_EXECUTOR = 1;
|
|
17
|
+
uint256 internal constant CONFIG_TYPE_ULN = 2;
|
|
18
|
+
|
|
19
|
+
error LZ_ULN_InvalidConfigType(uint256 configType);
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
address _endpoint,
|
|
23
|
+
uint256 _treasuryGasLimit,
|
|
24
|
+
uint256 _treasuryGasForFeeCap,
|
|
25
|
+
address _nonceContract,
|
|
26
|
+
uint32 _localEid,
|
|
27
|
+
address _treasuryFeeHandler
|
|
28
|
+
)
|
|
29
|
+
SendLibBaseE1(
|
|
30
|
+
_endpoint,
|
|
31
|
+
_treasuryGasLimit,
|
|
32
|
+
_treasuryGasForFeeCap,
|
|
33
|
+
_nonceContract,
|
|
34
|
+
_localEid,
|
|
35
|
+
_treasuryFeeHandler
|
|
36
|
+
)
|
|
37
|
+
{}
|
|
38
|
+
|
|
39
|
+
// ============================ OnlyEndpoint ===================================
|
|
40
|
+
|
|
41
|
+
function setConfig(
|
|
42
|
+
uint16 _eid,
|
|
43
|
+
address _oapp,
|
|
44
|
+
uint256 _configType,
|
|
45
|
+
bytes calldata _config
|
|
46
|
+
) external override onlyEndpoint {
|
|
47
|
+
_assertSupportedEid(_eid);
|
|
48
|
+
if (_configType == CONFIG_TYPE_EXECUTOR) {
|
|
49
|
+
_setExecutorConfig(_eid, _oapp, abi.decode(_config, (ExecutorConfig)));
|
|
50
|
+
} else if (_configType == CONFIG_TYPE_ULN) {
|
|
51
|
+
_setUlnConfig(_eid, _oapp, abi.decode(_config, (UlnConfig)));
|
|
52
|
+
} else {
|
|
53
|
+
revert LZ_ULN_InvalidConfigType(_configType);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================ View ===================================
|
|
58
|
+
|
|
59
|
+
function getConfig(uint16 _eid, address _oapp, uint256 _configType) external view override returns (bytes memory) {
|
|
60
|
+
if (_configType == CONFIG_TYPE_EXECUTOR) {
|
|
61
|
+
return abi.encode(getExecutorConfig(_oapp, _eid));
|
|
62
|
+
} else if (_configType == CONFIG_TYPE_ULN) {
|
|
63
|
+
return abi.encode(getUlnConfig(_oapp, _eid));
|
|
64
|
+
} else {
|
|
65
|
+
revert LZ_ULN_InvalidConfigType(_configType);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
|
|
70
|
+
return (3, 0, 1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isSupportedEid(uint32 _eid) external view returns (bool) {
|
|
74
|
+
return _isSupportedEid(_eid);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ============================ Internal ===================================
|
|
78
|
+
|
|
79
|
+
function _quoteVerifier(
|
|
80
|
+
address _sender,
|
|
81
|
+
uint32 _dstEid,
|
|
82
|
+
WorkerOptions[] memory _options
|
|
83
|
+
) internal view override returns (uint256) {
|
|
84
|
+
return _quoteDVNs(_sender, _dstEid, _options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function _payVerifier(
|
|
88
|
+
Packet memory _packet,
|
|
89
|
+
WorkerOptions[] memory _options
|
|
90
|
+
) internal virtual override returns (uint256 otherWorkerFees, bytes memory encodedPacket) {
|
|
91
|
+
(otherWorkerFees, encodedPacket) = _payDVNs(fees, _packet, _options);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _splitOptions(
|
|
95
|
+
bytes calldata _options
|
|
96
|
+
) internal pure override returns (bytes memory, WorkerOptions[] memory) {
|
|
97
|
+
return _splitUlnOptions(_options);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
6
|
+
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
+
|
|
8
|
+
import { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
|
|
9
|
+
|
|
10
|
+
import { ITreasuryFeeHandler } from "./interfaces/ITreasuryFeeHandler.sol";
|
|
11
|
+
|
|
12
|
+
contract TreasuryFeeHandler is ITreasuryFeeHandler {
|
|
13
|
+
using SafeERC20 for IERC20;
|
|
14
|
+
|
|
15
|
+
ILayerZeroEndpoint public immutable endpoint;
|
|
16
|
+
|
|
17
|
+
error LZ_TreasuryFeeHandler_OnlySendLibrary();
|
|
18
|
+
error LZ_TreasuryFeeHandler_OnlyOnSending();
|
|
19
|
+
error LZ_TreasuryFeeHandler_InvalidAmount(uint256 required, uint256 supplied);
|
|
20
|
+
|
|
21
|
+
constructor(address _endpoint) {
|
|
22
|
+
endpoint = ILayerZeroEndpoint(_endpoint);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// @dev payer of layerzero token must be sender
|
|
26
|
+
function payFee(
|
|
27
|
+
address _lzToken,
|
|
28
|
+
address _sender,
|
|
29
|
+
uint256 _required,
|
|
30
|
+
uint256 _supplied,
|
|
31
|
+
address _treasury
|
|
32
|
+
) external {
|
|
33
|
+
// only sender's message library can call this function and only when sending a payload
|
|
34
|
+
if (endpoint.getSendLibraryAddress(_sender) != msg.sender) revert LZ_TreasuryFeeHandler_OnlySendLibrary();
|
|
35
|
+
if (!endpoint.isSendingPayload()) revert LZ_TreasuryFeeHandler_OnlyOnSending();
|
|
36
|
+
if (_required > _supplied) revert LZ_TreasuryFeeHandler_InvalidAmount(_required, _supplied);
|
|
37
|
+
|
|
38
|
+
// send lz token fee to the treasury directly
|
|
39
|
+
IERC20(_lzToken).safeTransferFrom(_sender, _treasury, _required);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
import { ILayerZeroMessagingLibrary } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroMessagingLibrary.sol";
|
|
6
|
+
|
|
7
|
+
/// extends ILayerZeroMessagingLibrary instead of ILayerZeroMessagingLibraryV2 for reducing the contract size
|
|
8
|
+
interface IMessageLibE1 is ILayerZeroMessagingLibrary {
|
|
9
|
+
error LZ_MessageLib_InvalidPath();
|
|
10
|
+
error LZ_MessageLib_InvalidSender();
|
|
11
|
+
error LZ_MessageLib_InsufficientMsgValue();
|
|
12
|
+
error LZ_MessageLib_LzTokenPaymentAddressMustBeSender();
|
|
13
|
+
|
|
14
|
+
function setLzToken(address _lzToken) external;
|
|
15
|
+
|
|
16
|
+
function setTreasury(address _treasury) external;
|
|
17
|
+
|
|
18
|
+
function withdrawFee(address _to, uint256 _amount) external;
|
|
19
|
+
|
|
20
|
+
// message libs of same major version are compatible
|
|
21
|
+
function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion);
|
|
22
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.19;
|
|
4
|
+
|
|
5
|
+
import { ILayerZeroEndpoint } from "@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol";
|
|
6
|
+
|
|
7
|
+
contract NonceContractMock {
|
|
8
|
+
error OnlySendLibrary();
|
|
9
|
+
|
|
10
|
+
ILayerZeroEndpoint public immutable endpoint;
|
|
11
|
+
mapping(uint16 dstEid => mapping(bytes path => uint64 nonce)) public outboundNonce;
|
|
12
|
+
|
|
13
|
+
constructor(address _endpoint) {
|
|
14
|
+
endpoint = ILayerZeroEndpoint(_endpoint);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function increment(uint16 _chainId, address _ua, bytes calldata _path) external returns (uint64) {
|
|
18
|
+
if (msg.sender != endpoint.getSendLibraryAddress(_ua)) {
|
|
19
|
+
revert OnlySendLibrary();
|
|
20
|
+
}
|
|
21
|
+
return ++outboundNonce[_chainId][_path];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
|
|
6
|
+
import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";
|
|
7
|
+
import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
|
|
8
|
+
|
|
9
|
+
import { IReceiveUlnE2 } from "../interfaces/IReceiveUlnE2.sol";
|
|
10
|
+
import { ReceiveUlnBase } from "../ReceiveUlnBase.sol";
|
|
11
|
+
import { ReceiveLibBaseE2 } from "../../ReceiveLibBaseE2.sol";
|
|
12
|
+
import { UlnConfig } from "../UlnBase.sol";
|
|
13
|
+
|
|
14
|
+
/// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
|
|
15
|
+
/// @dev In this case, it combines the logic of ReceiveUlnBase and ReceiveLibBaseE2
|
|
16
|
+
contract ReceiveUln302 is IReceiveUlnE2, ReceiveUlnBase, ReceiveLibBaseE2 {
|
|
17
|
+
using PacketV1Codec for bytes;
|
|
18
|
+
|
|
19
|
+
/// @dev CONFIG_TYPE_ULN=2 here to align with SendUln302/ReceiveUln302/ReceiveUln301
|
|
20
|
+
uint32 internal constant CONFIG_TYPE_ULN = 2;
|
|
21
|
+
|
|
22
|
+
error LZ_ULN_InvalidConfigType(uint32 configType);
|
|
23
|
+
|
|
24
|
+
constructor(address _endpoint) ReceiveLibBaseE2(_endpoint) {}
|
|
25
|
+
|
|
26
|
+
function supportsInterface(bytes4 _interfaceId) public view override returns (bool) {
|
|
27
|
+
return _interfaceId == type(IReceiveUlnE2).interfaceId || super.supportsInterface(_interfaceId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================ OnlyEndpoint ===================================
|
|
31
|
+
|
|
32
|
+
// only the ULN config on the receive side
|
|
33
|
+
function setConfig(address _oapp, SetConfigParam[] calldata _params) external override onlyEndpoint {
|
|
34
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
35
|
+
SetConfigParam calldata param = _params[i];
|
|
36
|
+
_assertSupportedEid(param.eid);
|
|
37
|
+
if (param.configType == CONFIG_TYPE_ULN) {
|
|
38
|
+
_setUlnConfig(param.eid, _oapp, abi.decode(param.config, (UlnConfig)));
|
|
39
|
+
} else {
|
|
40
|
+
revert LZ_ULN_InvalidConfigType(param.configType);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ============================ External ===================================
|
|
46
|
+
|
|
47
|
+
/// @dev dont need to check endpoint verifiable here to save gas, as it will reverts if not verifiable.
|
|
48
|
+
function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external {
|
|
49
|
+
_assertHeader(_packetHeader, localEid);
|
|
50
|
+
|
|
51
|
+
// cache these values to save gas
|
|
52
|
+
address receiver = _packetHeader.receiverB20();
|
|
53
|
+
uint32 srcEid = _packetHeader.srcEid();
|
|
54
|
+
|
|
55
|
+
UlnConfig memory config = getUlnConfig(receiver, srcEid);
|
|
56
|
+
_verifyAndReclaimStorage(config, keccak256(_packetHeader), _payloadHash);
|
|
57
|
+
|
|
58
|
+
Origin memory origin = Origin(srcEid, _packetHeader.sender(), _packetHeader.nonce());
|
|
59
|
+
// endpoint will revert if nonce <= lazyInboundNonce
|
|
60
|
+
ILayerZeroEndpointV2(endpoint).verify(origin, receiver, _payloadHash);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @dev for dvn to verify the payload
|
|
64
|
+
function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external {
|
|
65
|
+
_verify(_packetHeader, _payloadHash, _confirmations);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================ View ===================================
|
|
69
|
+
|
|
70
|
+
function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view override returns (bytes memory) {
|
|
71
|
+
if (_configType == CONFIG_TYPE_ULN) {
|
|
72
|
+
return abi.encode(getUlnConfig(_oapp, _eid));
|
|
73
|
+
} else {
|
|
74
|
+
revert LZ_ULN_InvalidConfigType(_configType);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isSupportedEid(uint32 _eid) external view override returns (bool) {
|
|
79
|
+
return _isSupportedEid(_eid);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
|
|
83
|
+
return (3, 0, 2);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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 { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
|
|
7
|
+
import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
|
|
8
|
+
import { EndpointV2ViewUpgradeable } from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2ViewUpgradeable.sol";
|
|
9
|
+
import { UlnConfig } from "../UlnBase.sol";
|
|
10
|
+
|
|
11
|
+
enum VerificationState {
|
|
12
|
+
Verifying,
|
|
13
|
+
Verifiable,
|
|
14
|
+
Verified,
|
|
15
|
+
NotInitializable
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface IReceiveUln302 {
|
|
19
|
+
function assertHeader(bytes calldata _packetHeader, uint32 _localEid) external pure;
|
|
20
|
+
|
|
21
|
+
function verifiable(
|
|
22
|
+
UlnConfig memory _config,
|
|
23
|
+
bytes32 _headerHash,
|
|
24
|
+
bytes32 _payloadHash
|
|
25
|
+
) external view returns (bool);
|
|
26
|
+
|
|
27
|
+
function getUlnConfig(address _oapp, uint32 _remoteEid) external view returns (UlnConfig memory rtnConfig);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
contract ReceiveUln302View is EndpointV2ViewUpgradeable, Proxied {
|
|
31
|
+
using PacketV1Codec for bytes;
|
|
32
|
+
|
|
33
|
+
IReceiveUln302 public receiveUln302;
|
|
34
|
+
uint32 internal localEid;
|
|
35
|
+
|
|
36
|
+
function initialize(address _endpoint, address _receiveUln302) external proxied initializer {
|
|
37
|
+
__EndpointV2View_init(_endpoint);
|
|
38
|
+
receiveUln302 = IReceiveUln302(_receiveUln302);
|
|
39
|
+
localEid = endpoint.eid();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// @dev a ULN verifiable requires it to be endpoint verifiable and committable
|
|
43
|
+
function verifiable(bytes calldata _packetHeader, bytes32 _payloadHash) external view returns (VerificationState) {
|
|
44
|
+
receiveUln302.assertHeader(_packetHeader, localEid);
|
|
45
|
+
|
|
46
|
+
address receiver = _packetHeader.receiverB20();
|
|
47
|
+
|
|
48
|
+
Origin memory origin = Origin(_packetHeader.srcEid(), _packetHeader.sender(), _packetHeader.nonce());
|
|
49
|
+
|
|
50
|
+
// check endpoint initializable
|
|
51
|
+
if (!initializable(origin, receiver)) {
|
|
52
|
+
return VerificationState.NotInitializable;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// check endpoint verifiable
|
|
56
|
+
if (!_endpointVerifiable(origin, receiver, _payloadHash)) {
|
|
57
|
+
return VerificationState.Verified;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// check uln verifiable
|
|
61
|
+
if (
|
|
62
|
+
receiveUln302.verifiable(
|
|
63
|
+
receiveUln302.getUlnConfig(receiver, origin.srcEid),
|
|
64
|
+
keccak256(_packetHeader),
|
|
65
|
+
_payloadHash
|
|
66
|
+
)
|
|
67
|
+
) {
|
|
68
|
+
return VerificationState.Verifiable;
|
|
69
|
+
}
|
|
70
|
+
return VerificationState.Verifying;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// @dev checks for endpoint verifiable and endpoint has payload hash
|
|
74
|
+
function _endpointVerifiable(
|
|
75
|
+
Origin memory origin,
|
|
76
|
+
address _receiver,
|
|
77
|
+
bytes32 _payloadHash
|
|
78
|
+
) internal view returns (bool) {
|
|
79
|
+
// check endpoint verifiable
|
|
80
|
+
if (!verifiable(origin, _receiver, address(receiveUln302), _payloadHash)) return false;
|
|
81
|
+
|
|
82
|
+
// if endpoint.verifiable, also check if the payload hash matches
|
|
83
|
+
// endpoint allows re-verify, check if this payload has already been verified
|
|
84
|
+
if (endpoint.inboundPayloadHash(_receiver, origin.srcEid, origin.sender, origin.nonce) == _payloadHash)
|
|
85
|
+
return false;
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
6
|
+
import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol";
|
|
7
|
+
|
|
8
|
+
import { ExecutorConfig } from "../../SendLibBase.sol";
|
|
9
|
+
import { SendLibBaseE2, WorkerOptions } from "../../SendLibBaseE2.sol";
|
|
10
|
+
import { UlnConfig } from "../UlnBase.sol";
|
|
11
|
+
import { SendUlnBase } from "../SendUlnBase.sol";
|
|
12
|
+
|
|
13
|
+
/// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly.
|
|
14
|
+
/// @dev In this case, it combines the logic of SendUlnBase and SendLibBaseE2
|
|
15
|
+
contract SendUln302 is SendUlnBase, SendLibBaseE2 {
|
|
16
|
+
uint32 internal constant CONFIG_TYPE_EXECUTOR = 1;
|
|
17
|
+
uint32 internal constant CONFIG_TYPE_ULN = 2;
|
|
18
|
+
|
|
19
|
+
error LZ_ULN_InvalidConfigType(uint32 configType);
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
address _endpoint,
|
|
23
|
+
uint256 _treasuryGasLimit,
|
|
24
|
+
uint256 _treasuryGasForFeeCap
|
|
25
|
+
) SendLibBaseE2(_endpoint, _treasuryGasLimit, _treasuryGasForFeeCap) {}
|
|
26
|
+
|
|
27
|
+
// ============================ OnlyEndpoint ===================================
|
|
28
|
+
|
|
29
|
+
// on the send side the user can config both the executor and the ULN
|
|
30
|
+
function setConfig(address _oapp, SetConfigParam[] calldata _params) external override onlyEndpoint {
|
|
31
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
32
|
+
SetConfigParam calldata param = _params[i];
|
|
33
|
+
_assertSupportedEid(param.eid);
|
|
34
|
+
if (param.configType == CONFIG_TYPE_EXECUTOR) {
|
|
35
|
+
_setExecutorConfig(param.eid, _oapp, abi.decode(param.config, (ExecutorConfig)));
|
|
36
|
+
} else if (param.configType == CONFIG_TYPE_ULN) {
|
|
37
|
+
_setUlnConfig(param.eid, _oapp, abi.decode(param.config, (UlnConfig)));
|
|
38
|
+
} else {
|
|
39
|
+
revert LZ_ULN_InvalidConfigType(param.configType);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ============================ View ===================================
|
|
45
|
+
|
|
46
|
+
function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view override returns (bytes memory) {
|
|
47
|
+
if (_configType == CONFIG_TYPE_EXECUTOR) {
|
|
48
|
+
return abi.encode(getExecutorConfig(_oapp, _eid));
|
|
49
|
+
} else if (_configType == CONFIG_TYPE_ULN) {
|
|
50
|
+
return abi.encode(getUlnConfig(_oapp, _eid));
|
|
51
|
+
} else {
|
|
52
|
+
revert LZ_ULN_InvalidConfigType(_configType);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) {
|
|
57
|
+
return (3, 0, 2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isSupportedEid(uint32 _eid) external view override returns (bool) {
|
|
61
|
+
return _isSupportedEid(_eid);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================ Internal ===================================
|
|
65
|
+
|
|
66
|
+
function _quoteVerifier(
|
|
67
|
+
address _sender,
|
|
68
|
+
uint32 _dstEid,
|
|
69
|
+
WorkerOptions[] memory _options
|
|
70
|
+
) internal view override returns (uint256) {
|
|
71
|
+
return _quoteDVNs(_sender, _dstEid, _options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function _payVerifier(
|
|
75
|
+
Packet calldata _packet,
|
|
76
|
+
WorkerOptions[] memory _options
|
|
77
|
+
) internal override returns (uint256 otherWorkerFees, bytes memory encodedPacket) {
|
|
78
|
+
(otherWorkerFees, encodedPacket) = _payDVNs(fees, _packet, _options);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function _splitOptions(
|
|
82
|
+
bytes calldata _options
|
|
83
|
+
) internal pure override returns (bytes memory, WorkerOptions[] memory) {
|
|
84
|
+
return _splitUlnOptions(_options);
|
|
85
|
+
}
|
|
86
|
+
}
|