@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
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `@layerzerolabs/protocol-v2-messagelib-evm-contracts`
|
|
2
|
+
|
|
3
|
+
LayerZero V2 EVM message libraries (ULN 301/302, read library), DVN, executor, price feed and treasury contracts. Its sources import `@layerzerolabs/lz-evm-protocol-v2` and `@layerzerolabs/lz-evm-v1-0.7`, which resolve to the workspace copies through package aliases, so the source names, and with them the metadata hashes, stay as published.
|
|
4
|
+
|
|
5
|
+
Copied byte for byte from `@layerzerolabs/lz-evm-messagelib-v2` (`packages/layerzero-v2/evm/messagelib`) in the old LayerZero-Labs/monorepo at `origin/cb/executor-upgrade` (`d976cafeaf`). Only `contracts/` and the Foundry tests are copied; the old deploy scripts, deployment records, typechain bindings and Hardhat tests are not.
|
|
6
|
+
|
|
7
|
+
## Build
|
|
8
|
+
|
|
9
|
+
`pnpm build` compiles with the old compiler settings (`hardhat.config.cjs`) into `artifacts/` (EVM), `artifacts-zk/` (zkSync) and `artifacts-tron/` (Tron), which the package publishes for consumers to read by path, e.g. `@layerzerolabs/protocol-v2-messagelib-evm-contracts/artifacts/contracts/<Source>.sol/<Contract>.json`.
|
|
10
|
+
|
|
11
|
+
`../scripts/compare-artifacts.mjs` compares the compiled bytecode with the artifacts the old monorepo published.
|
|
12
|
+
|
|
13
|
+
## Test
|
|
14
|
+
|
|
15
|
+
`pnpm test` runs the Foundry tests.
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
|
|
6
|
+
import { Proxied } from "hardhat-deploy/solc_0.8/proxy/Proxied.sol";
|
|
7
|
+
|
|
8
|
+
import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
|
|
9
|
+
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
|
|
10
|
+
|
|
11
|
+
import { IUltraLightNode301 } from "./uln/uln301/interfaces/IUltraLightNode301.sol";
|
|
12
|
+
import { IExecutor } from "./interfaces/IExecutor.sol";
|
|
13
|
+
import { IExecutorFeeLib } from "./interfaces/IExecutorFeeLib.sol";
|
|
14
|
+
import { WorkerUpgradeable } from "./upgradeable/WorkerUpgradeable.sol";
|
|
15
|
+
|
|
16
|
+
interface ILayerZeroEndpointV2 {
|
|
17
|
+
function eid() external view returns (uint32);
|
|
18
|
+
|
|
19
|
+
function lzReceive(
|
|
20
|
+
Origin calldata _origin,
|
|
21
|
+
address _receiver,
|
|
22
|
+
bytes32 _guid,
|
|
23
|
+
bytes calldata _message,
|
|
24
|
+
bytes calldata _extraData
|
|
25
|
+
) external payable;
|
|
26
|
+
|
|
27
|
+
function lzReceiveAlert(
|
|
28
|
+
Origin calldata _origin,
|
|
29
|
+
address _receiver,
|
|
30
|
+
bytes32 _guid,
|
|
31
|
+
uint256 _gas,
|
|
32
|
+
uint256 _value,
|
|
33
|
+
bytes calldata _message,
|
|
34
|
+
bytes calldata _extraData,
|
|
35
|
+
bytes calldata _reason
|
|
36
|
+
) external;
|
|
37
|
+
|
|
38
|
+
function lzCompose(
|
|
39
|
+
address _from,
|
|
40
|
+
address _to,
|
|
41
|
+
bytes32 _guid,
|
|
42
|
+
uint16 _index,
|
|
43
|
+
bytes calldata _message,
|
|
44
|
+
bytes calldata _extraData
|
|
45
|
+
) external payable;
|
|
46
|
+
|
|
47
|
+
function lzComposeAlert(
|
|
48
|
+
address _from,
|
|
49
|
+
address _to,
|
|
50
|
+
bytes32 _guid,
|
|
51
|
+
uint16 _index,
|
|
52
|
+
uint256 _gas,
|
|
53
|
+
uint256 _value,
|
|
54
|
+
bytes calldata _message,
|
|
55
|
+
bytes calldata _extraData,
|
|
56
|
+
bytes calldata _reason
|
|
57
|
+
) external;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
contract Executor is WorkerUpgradeable, ReentrancyGuardUpgradeable, Proxied, IExecutor {
|
|
61
|
+
using PacketV1Codec for bytes;
|
|
62
|
+
|
|
63
|
+
mapping(uint32 dstEid => DstConfig) public dstConfig;
|
|
64
|
+
|
|
65
|
+
// endpoint v2
|
|
66
|
+
address public endpoint;
|
|
67
|
+
uint32 public localEidV2;
|
|
68
|
+
|
|
69
|
+
// endpoint v1
|
|
70
|
+
address public receiveUln301;
|
|
71
|
+
|
|
72
|
+
event ReceiveUln301Set(address receiveUln301);
|
|
73
|
+
event PriceFloorWhitelistSet(address indexed sender, bool whitelisted);
|
|
74
|
+
|
|
75
|
+
// Senders quoted and charged the multiplier price, with no USD floor.
|
|
76
|
+
mapping(address sender => bool whitelisted) public priceFloorWhitelist;
|
|
77
|
+
|
|
78
|
+
struct SetPriceFloorWhitelistParam {
|
|
79
|
+
address sender;
|
|
80
|
+
bool whitelisted;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function initialize(
|
|
84
|
+
address _endpoint,
|
|
85
|
+
address _receiveUln301,
|
|
86
|
+
address[] memory _messageLibs,
|
|
87
|
+
address _priceFeed,
|
|
88
|
+
address _roleAdmin,
|
|
89
|
+
address[] memory _admins
|
|
90
|
+
) external proxied initializer {
|
|
91
|
+
__ReentrancyGuard_init();
|
|
92
|
+
__Worker_init(_messageLibs, _priceFeed, 12000, _roleAdmin, _admins);
|
|
93
|
+
endpoint = _endpoint;
|
|
94
|
+
localEidV2 = ILayerZeroEndpointV2(_endpoint).eid();
|
|
95
|
+
receiveUln301 = _receiveUln301;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function onUpgrade(address _receiveUln301) external proxied {
|
|
99
|
+
receiveUln301 = _receiveUln301;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// --- Admin ---
|
|
103
|
+
function setDstConfig(DstConfigParam[] memory _params) external onlyRole(ADMIN_ROLE) {
|
|
104
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
105
|
+
DstConfigParam memory param = _params[i];
|
|
106
|
+
dstConfig[param.dstEid] = DstConfig(
|
|
107
|
+
param.lzReceiveBaseGas,
|
|
108
|
+
param.multiplierBps,
|
|
109
|
+
param.floorMarginUSD,
|
|
110
|
+
param.nativeCap,
|
|
111
|
+
param.lzComposeBaseGas
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
emit DstConfigSet(_params);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setReceiveUln301(address _receiveUln301) external onlyRole(ADMIN_ROLE) {
|
|
118
|
+
receiveUln301 = _receiveUln301;
|
|
119
|
+
emit ReceiveUln301Set(_receiveUln301);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// @notice Mark senders that pay the default multiplier price and skip the USD price floor.
|
|
123
|
+
function setPriceFloorWhitelist(SetPriceFloorWhitelistParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
|
|
124
|
+
for (uint256 i = 0; i < _params.length; i++) {
|
|
125
|
+
SetPriceFloorWhitelistParam calldata param = _params[i];
|
|
126
|
+
priceFloorWhitelist[param.sender] = param.whitelisted;
|
|
127
|
+
emit PriceFloorWhitelistSet(param.sender, param.whitelisted);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function nativeDrop(
|
|
132
|
+
Origin calldata _origin,
|
|
133
|
+
uint32 _dstEid,
|
|
134
|
+
address _oapp,
|
|
135
|
+
NativeDropParams[] calldata _nativeDropParams,
|
|
136
|
+
uint256 _nativeDropGasLimit
|
|
137
|
+
) external payable onlyRole(ADMIN_ROLE) nonReentrant {
|
|
138
|
+
_nativeDrop(_origin, _dstEid, _oapp, _nativeDropParams, _nativeDropGasLimit);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function nativeDropAndExecute301(
|
|
142
|
+
Origin calldata _origin,
|
|
143
|
+
NativeDropParams[] calldata _nativeDropParams,
|
|
144
|
+
uint256 _nativeDropGasLimit,
|
|
145
|
+
bytes calldata _packet,
|
|
146
|
+
uint256 _gasLimit
|
|
147
|
+
) external payable onlyRole(ADMIN_ROLE) nonReentrant {
|
|
148
|
+
_nativeDrop(_origin, _packet.dstEid(), _packet.receiverB20(), _nativeDropParams, _nativeDropGasLimit);
|
|
149
|
+
IUltraLightNode301(receiveUln301).commitVerification(_packet, _gasLimit);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function execute301(bytes calldata _packet, uint256 _gasLimit) external onlyRole(ADMIN_ROLE) nonReentrant {
|
|
153
|
+
IUltraLightNode301(receiveUln301).commitVerification(_packet, _gasLimit);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function execute302(ExecutionParams calldata _executionParams) external payable onlyRole(ADMIN_ROLE) nonReentrant {
|
|
157
|
+
try
|
|
158
|
+
ILayerZeroEndpointV2(endpoint).lzReceive{ value: msg.value, gas: _executionParams.gasLimit }(
|
|
159
|
+
_executionParams.origin,
|
|
160
|
+
_executionParams.receiver,
|
|
161
|
+
_executionParams.guid,
|
|
162
|
+
_executionParams.message,
|
|
163
|
+
_executionParams.extraData
|
|
164
|
+
)
|
|
165
|
+
{
|
|
166
|
+
// do nothing
|
|
167
|
+
} catch (bytes memory reason) {
|
|
168
|
+
ILayerZeroEndpointV2(endpoint).lzReceiveAlert(
|
|
169
|
+
_executionParams.origin,
|
|
170
|
+
_executionParams.receiver,
|
|
171
|
+
_executionParams.guid,
|
|
172
|
+
_executionParams.gasLimit,
|
|
173
|
+
msg.value,
|
|
174
|
+
_executionParams.message,
|
|
175
|
+
_executionParams.extraData,
|
|
176
|
+
reason
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function compose302(
|
|
182
|
+
address _from,
|
|
183
|
+
address _to,
|
|
184
|
+
bytes32 _guid,
|
|
185
|
+
uint16 _index,
|
|
186
|
+
bytes calldata _message,
|
|
187
|
+
bytes calldata _extraData,
|
|
188
|
+
uint256 _gasLimit
|
|
189
|
+
) external payable onlyRole(ADMIN_ROLE) nonReentrant {
|
|
190
|
+
try
|
|
191
|
+
ILayerZeroEndpointV2(endpoint).lzCompose{ value: msg.value, gas: _gasLimit }(
|
|
192
|
+
_from,
|
|
193
|
+
_to,
|
|
194
|
+
_guid,
|
|
195
|
+
_index,
|
|
196
|
+
_message,
|
|
197
|
+
_extraData
|
|
198
|
+
)
|
|
199
|
+
{
|
|
200
|
+
// do nothing
|
|
201
|
+
} catch (bytes memory reason) {
|
|
202
|
+
ILayerZeroEndpointV2(endpoint).lzComposeAlert(
|
|
203
|
+
_from,
|
|
204
|
+
_to,
|
|
205
|
+
_guid,
|
|
206
|
+
_index,
|
|
207
|
+
_gasLimit,
|
|
208
|
+
msg.value,
|
|
209
|
+
_message,
|
|
210
|
+
_extraData,
|
|
211
|
+
reason
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function nativeDropAndExecute302(
|
|
217
|
+
NativeDropParams[] calldata _nativeDropParams,
|
|
218
|
+
uint256 _nativeDropGasLimit,
|
|
219
|
+
ExecutionParams calldata _executionParams
|
|
220
|
+
) external payable onlyRole(ADMIN_ROLE) nonReentrant {
|
|
221
|
+
uint256 spent = _nativeDrop(
|
|
222
|
+
_executionParams.origin,
|
|
223
|
+
localEidV2,
|
|
224
|
+
_executionParams.receiver,
|
|
225
|
+
_nativeDropParams,
|
|
226
|
+
_nativeDropGasLimit
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
uint256 value = msg.value - spent;
|
|
230
|
+
try
|
|
231
|
+
ILayerZeroEndpointV2(endpoint).lzReceive{ value: value, gas: _executionParams.gasLimit }(
|
|
232
|
+
_executionParams.origin,
|
|
233
|
+
_executionParams.receiver,
|
|
234
|
+
_executionParams.guid,
|
|
235
|
+
_executionParams.message,
|
|
236
|
+
_executionParams.extraData
|
|
237
|
+
)
|
|
238
|
+
{
|
|
239
|
+
// do nothing
|
|
240
|
+
} catch (bytes memory reason) {
|
|
241
|
+
ILayerZeroEndpointV2(endpoint).lzReceiveAlert(
|
|
242
|
+
_executionParams.origin,
|
|
243
|
+
_executionParams.receiver,
|
|
244
|
+
_executionParams.guid,
|
|
245
|
+
_executionParams.gasLimit,
|
|
246
|
+
value,
|
|
247
|
+
_executionParams.message,
|
|
248
|
+
_executionParams.extraData,
|
|
249
|
+
reason
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// --- Message Lib ---
|
|
255
|
+
function assignJob(
|
|
256
|
+
uint32 _dstEid,
|
|
257
|
+
address _sender,
|
|
258
|
+
uint256 _calldataSize,
|
|
259
|
+
bytes calldata _options
|
|
260
|
+
) external onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
|
|
261
|
+
IExecutorFeeLib.FeeParams memory params = IExecutorFeeLib.FeeParams(
|
|
262
|
+
priceFeed,
|
|
263
|
+
_dstEid,
|
|
264
|
+
_sender,
|
|
265
|
+
_calldataSize,
|
|
266
|
+
defaultMultiplierBps
|
|
267
|
+
);
|
|
268
|
+
fee = IExecutorFeeLib(workerFeeLib).getFeeOnSend(params, _configForSender(_dstEid, _sender), _options);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// assignJob for ReadLib
|
|
272
|
+
function assignJob(
|
|
273
|
+
address _sender,
|
|
274
|
+
bytes calldata _options
|
|
275
|
+
) external onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
|
|
276
|
+
IExecutorFeeLib.FeeParamsForRead memory params = IExecutorFeeLib.FeeParamsForRead(
|
|
277
|
+
priceFeed,
|
|
278
|
+
_sender,
|
|
279
|
+
defaultMultiplierBps
|
|
280
|
+
);
|
|
281
|
+
fee = IExecutorFeeLib(workerFeeLib).getFeeOnSend(params, _configForSender(localEidV2, _sender), _options);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// --- Only ACL ---
|
|
285
|
+
function getFee(
|
|
286
|
+
uint32 _dstEid,
|
|
287
|
+
address _sender,
|
|
288
|
+
uint256 _calldataSize,
|
|
289
|
+
bytes calldata _options
|
|
290
|
+
) external view onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
|
|
291
|
+
IExecutorFeeLib.FeeParams memory params = IExecutorFeeLib.FeeParams(
|
|
292
|
+
priceFeed,
|
|
293
|
+
_dstEid,
|
|
294
|
+
_sender,
|
|
295
|
+
_calldataSize,
|
|
296
|
+
defaultMultiplierBps
|
|
297
|
+
);
|
|
298
|
+
fee = IExecutorFeeLib(workerFeeLib).getFee(params, _configForSender(_dstEid, _sender), _options);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getFee(
|
|
302
|
+
address _sender,
|
|
303
|
+
bytes calldata _options
|
|
304
|
+
) external view onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
|
|
305
|
+
IExecutorFeeLib.FeeParamsForRead memory params = IExecutorFeeLib.FeeParamsForRead(
|
|
306
|
+
priceFeed,
|
|
307
|
+
_sender,
|
|
308
|
+
defaultMultiplierBps
|
|
309
|
+
);
|
|
310
|
+
fee = IExecutorFeeLib(workerFeeLib).getFee(params, _configForSender(localEidV2, _sender), _options);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/// @dev Whitelisted senders keep multiplier pricing and have the USD floor cleared.
|
|
314
|
+
function _configForSender(uint32 _dstEid, address _sender) internal view returns (DstConfig memory config) {
|
|
315
|
+
config = dstConfig[_dstEid];
|
|
316
|
+
if (priceFloorWhitelist[_sender]) {
|
|
317
|
+
config.floorMarginUSD = 0;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function _nativeDrop(
|
|
322
|
+
Origin calldata _origin,
|
|
323
|
+
uint32 _dstEid,
|
|
324
|
+
address _oapp,
|
|
325
|
+
NativeDropParams[] calldata _nativeDropParams,
|
|
326
|
+
uint256 _nativeDropGasLimit
|
|
327
|
+
) internal returns (uint256 spent) {
|
|
328
|
+
bool[] memory success = new bool[](_nativeDropParams.length);
|
|
329
|
+
for (uint256 i = 0; i < _nativeDropParams.length; i++) {
|
|
330
|
+
NativeDropParams memory param = _nativeDropParams[i];
|
|
331
|
+
|
|
332
|
+
(bool sent, ) = param.receiver.call{ value: param.amount, gas: _nativeDropGasLimit }("");
|
|
333
|
+
|
|
334
|
+
success[i] = sent;
|
|
335
|
+
spent += param.amount;
|
|
336
|
+
}
|
|
337
|
+
emit NativeDropApplied(_origin, _dstEid, _oapp, _nativeDropParams, success);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
|
6
|
+
|
|
7
|
+
import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
|
|
8
|
+
|
|
9
|
+
import { ILayerZeroPriceFeed } from "./interfaces/ILayerZeroPriceFeed.sol";
|
|
10
|
+
import { IExecutor } from "./interfaces/IExecutor.sol";
|
|
11
|
+
import { IExecutorFeeLib } from "./interfaces/IExecutorFeeLib.sol";
|
|
12
|
+
import { ExecutorOptions } from "./libs/ExecutorOptions.sol";
|
|
13
|
+
|
|
14
|
+
contract ExecutorFeeLib is Ownable, IExecutorFeeLib {
|
|
15
|
+
using ExecutorOptions for bytes;
|
|
16
|
+
|
|
17
|
+
uint256 private immutable nativeDecimalsRate;
|
|
18
|
+
uint32 private immutable localEidV2; // endpoint-v2 only, for read call
|
|
19
|
+
|
|
20
|
+
constructor(uint32 _localEidV2, uint256 _nativeDecimalsRate) {
|
|
21
|
+
localEidV2 = _localEidV2;
|
|
22
|
+
nativeDecimalsRate = _nativeDecimalsRate;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ================================ OnlyOwner ================================
|
|
26
|
+
function withdrawToken(address _token, address _to, uint256 _amount) external onlyOwner {
|
|
27
|
+
// transfers native if _token is address(0x0)
|
|
28
|
+
Transfer.nativeOrToken(_token, _to, _amount);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ================================ External ================================
|
|
32
|
+
function getFeeOnSend(
|
|
33
|
+
FeeParams calldata _params,
|
|
34
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
35
|
+
bytes calldata _options
|
|
36
|
+
) external view returns (uint256 fee) {
|
|
37
|
+
fee = getFee(_params, _dstConfig, _options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getFeeOnSend(
|
|
41
|
+
FeeParamsForRead calldata _params,
|
|
42
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
43
|
+
bytes calldata _options
|
|
44
|
+
) external view returns (uint256 fee) {
|
|
45
|
+
fee = getFee(_params, _dstConfig, _options);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ================================ View ================================
|
|
49
|
+
function getFee(
|
|
50
|
+
FeeParams calldata _params,
|
|
51
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
52
|
+
bytes calldata _options
|
|
53
|
+
) public view returns (uint256 fee) {
|
|
54
|
+
if (_dstConfig.lzReceiveBaseGas == 0) revert Executor_EidNotSupported(_params.dstEid);
|
|
55
|
+
|
|
56
|
+
(uint256 totalValue, uint256 totalGas, ) = _decodeExecutorOptions(
|
|
57
|
+
false,
|
|
58
|
+
_isV1Eid(_params.dstEid),
|
|
59
|
+
_dstConfig.lzReceiveBaseGas,
|
|
60
|
+
_dstConfig.lzComposeBaseGas,
|
|
61
|
+
_dstConfig.nativeCap,
|
|
62
|
+
_options
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
(
|
|
66
|
+
uint256 totalGasFee,
|
|
67
|
+
uint128 priceRatio,
|
|
68
|
+
uint128 priceRatioDenominator,
|
|
69
|
+
uint128 nativePriceUSD
|
|
70
|
+
) = ILayerZeroPriceFeed(_params.priceFeed).estimateFeeByEid(_params.dstEid, _params.calldataSize, totalGas);
|
|
71
|
+
|
|
72
|
+
uint16 multiplierBps = _dstConfig.multiplierBps == 0 ? _params.defaultMultiplierBps : _dstConfig.multiplierBps;
|
|
73
|
+
|
|
74
|
+
fee = _applyPremiumToGas(totalGasFee, multiplierBps, _dstConfig.floorMarginUSD, nativePriceUSD);
|
|
75
|
+
fee += _convertAndApplyPremiumToValue(totalValue, priceRatio, priceRatioDenominator, multiplierBps);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getFee(
|
|
79
|
+
FeeParamsForRead calldata _params,
|
|
80
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
81
|
+
bytes calldata _options
|
|
82
|
+
) public view returns (uint256 fee) {
|
|
83
|
+
if (_dstConfig.lzReceiveBaseGas == 0) revert Executor_EidNotSupported(localEidV2);
|
|
84
|
+
|
|
85
|
+
(uint256 totalValue, uint256 totalGas, uint32 calldataSize) = _decodeExecutorOptions(
|
|
86
|
+
true,
|
|
87
|
+
false, // endpoint v2 only
|
|
88
|
+
_dstConfig.lzReceiveBaseGas,
|
|
89
|
+
_dstConfig.lzComposeBaseGas,
|
|
90
|
+
_dstConfig.nativeCap,
|
|
91
|
+
_options
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
(
|
|
95
|
+
uint256 totalGasFee,
|
|
96
|
+
uint128 priceRatio,
|
|
97
|
+
uint128 priceRatioDenominator,
|
|
98
|
+
uint128 nativePriceUSD
|
|
99
|
+
) = ILayerZeroPriceFeed(_params.priceFeed).estimateFeeByEid(localEidV2, calldataSize, totalGas);
|
|
100
|
+
|
|
101
|
+
uint16 multiplierBps = _dstConfig.multiplierBps == 0 ? _params.defaultMultiplierBps : _dstConfig.multiplierBps;
|
|
102
|
+
|
|
103
|
+
fee = _applyPremiumToGas(totalGasFee, multiplierBps, _dstConfig.floorMarginUSD, nativePriceUSD);
|
|
104
|
+
fee += _convertAndApplyPremiumToValue(totalValue, priceRatio, priceRatioDenominator, multiplierBps);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ================================ Internal ================================
|
|
108
|
+
// @dev decode executor options into dstAmount and totalGas
|
|
109
|
+
function _decodeExecutorOptions(
|
|
110
|
+
bool _isRead,
|
|
111
|
+
bool _v1Eid,
|
|
112
|
+
uint64 _lzReceiveBaseGas,
|
|
113
|
+
uint64 _lzComposeBaseGas,
|
|
114
|
+
uint128 _nativeCap,
|
|
115
|
+
bytes calldata _options
|
|
116
|
+
) internal pure returns (uint256 totalValue, uint256 totalGas, uint32 calldataSize) {
|
|
117
|
+
ExecutorOptionsAgg memory aggOptions = _parseExecutorOptions(_options, _isRead, _v1Eid, _nativeCap);
|
|
118
|
+
totalValue = aggOptions.totalValue;
|
|
119
|
+
calldataSize = aggOptions.calldataSize;
|
|
120
|
+
|
|
121
|
+
// lz receive only called once
|
|
122
|
+
// lz compose can be called multiple times, based on unique index
|
|
123
|
+
// to simplify the quoting, we add lzComposeBaseGas for each lzComposeOption received
|
|
124
|
+
// if the same index has multiple compose options, the gas will be added multiple times
|
|
125
|
+
totalGas = _lzReceiveBaseGas + aggOptions.totalGas + _lzComposeBaseGas * aggOptions.numLzCompose;
|
|
126
|
+
if (aggOptions.ordered) {
|
|
127
|
+
totalGas = (totalGas * 102) / 100;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
struct ExecutorOptionsAgg {
|
|
132
|
+
uint256 totalValue;
|
|
133
|
+
uint256 totalGas;
|
|
134
|
+
bool ordered;
|
|
135
|
+
uint32 calldataSize;
|
|
136
|
+
uint256 numLzCompose;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function _parseExecutorOptions(
|
|
140
|
+
bytes calldata _options,
|
|
141
|
+
bool _isRead,
|
|
142
|
+
bool _v1Eid,
|
|
143
|
+
uint128 _nativeCap
|
|
144
|
+
) internal pure returns (ExecutorOptionsAgg memory options) {
|
|
145
|
+
if (_options.length == 0) {
|
|
146
|
+
revert Executor_NoOptions();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
uint256 cursor = 0;
|
|
150
|
+
uint256 lzReceiveGas;
|
|
151
|
+
uint32 calldataSize;
|
|
152
|
+
while (cursor < _options.length) {
|
|
153
|
+
(uint8 optionType, bytes calldata option, uint256 newCursor) = _options.nextExecutorOption(cursor);
|
|
154
|
+
cursor = newCursor;
|
|
155
|
+
|
|
156
|
+
if (optionType == ExecutorOptions.OPTION_TYPE_LZRECEIVE) {
|
|
157
|
+
// lzRead does not support lzReceive option
|
|
158
|
+
if (_isRead) revert Executor_UnsupportedOptionType(optionType);
|
|
159
|
+
(uint128 gas, uint128 value) = ExecutorOptions.decodeLzReceiveOption(option);
|
|
160
|
+
|
|
161
|
+
// endpoint v1 does not support lzReceive with value
|
|
162
|
+
if (_v1Eid && value > 0) revert Executor_UnsupportedOptionType(optionType);
|
|
163
|
+
|
|
164
|
+
options.totalValue += value;
|
|
165
|
+
lzReceiveGas += gas;
|
|
166
|
+
} else if (optionType == ExecutorOptions.OPTION_TYPE_NATIVE_DROP) {
|
|
167
|
+
// lzRead does not support nativeDrop option
|
|
168
|
+
if (_isRead) revert Executor_UnsupportedOptionType(optionType);
|
|
169
|
+
|
|
170
|
+
(uint128 nativeDropAmount, ) = ExecutorOptions.decodeNativeDropOption(option);
|
|
171
|
+
options.totalValue += nativeDropAmount;
|
|
172
|
+
} else if (optionType == ExecutorOptions.OPTION_TYPE_LZCOMPOSE) {
|
|
173
|
+
// endpoint v1 does not support lzCompose
|
|
174
|
+
if (_v1Eid) revert Executor_UnsupportedOptionType(optionType);
|
|
175
|
+
|
|
176
|
+
(, uint128 gas, uint128 value) = ExecutorOptions.decodeLzComposeOption(option);
|
|
177
|
+
if (gas == 0) revert Executor_ZeroLzComposeGasProvided();
|
|
178
|
+
|
|
179
|
+
options.totalValue += value;
|
|
180
|
+
options.totalGas += gas;
|
|
181
|
+
options.numLzCompose++;
|
|
182
|
+
} else if (optionType == ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION) {
|
|
183
|
+
options.ordered = true;
|
|
184
|
+
} else if (optionType == ExecutorOptions.OPTION_TYPE_LZREAD) {
|
|
185
|
+
if (!_isRead) revert Executor_UnsupportedOptionType(optionType);
|
|
186
|
+
|
|
187
|
+
(uint128 gas, uint32 size, uint128 value) = ExecutorOptions.decodeLzReadOption(option);
|
|
188
|
+
options.totalValue += value;
|
|
189
|
+
lzReceiveGas += gas;
|
|
190
|
+
calldataSize += size;
|
|
191
|
+
} else {
|
|
192
|
+
revert Executor_UnsupportedOptionType(optionType);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (cursor != _options.length) revert Executor_InvalidExecutorOptions(cursor);
|
|
196
|
+
if (options.totalValue > _nativeCap) revert Executor_NativeAmountExceedsCap(options.totalValue, _nativeCap);
|
|
197
|
+
if (lzReceiveGas == 0) revert Executor_ZeroLzReceiveGasProvided();
|
|
198
|
+
if (_isRead && calldataSize == 0) revert Executor_ZeroCalldataSizeProvided();
|
|
199
|
+
options.totalGas += lzReceiveGas;
|
|
200
|
+
options.calldataSize = calldataSize;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function _applyPremiumToGas(
|
|
204
|
+
uint256 _fee,
|
|
205
|
+
uint16 _multiplierBps,
|
|
206
|
+
uint128 _marginUSD,
|
|
207
|
+
uint128 _nativePriceUSD
|
|
208
|
+
) internal view returns (uint256) {
|
|
209
|
+
uint256 feeWithMultiplier = (_fee * _multiplierBps) / 10000;
|
|
210
|
+
|
|
211
|
+
if (_nativePriceUSD == 0 || _marginUSD == 0) {
|
|
212
|
+
return feeWithMultiplier;
|
|
213
|
+
}
|
|
214
|
+
uint256 feeWithMargin = (_marginUSD * nativeDecimalsRate) / _nativePriceUSD + _fee;
|
|
215
|
+
return feeWithMargin > feeWithMultiplier ? feeWithMargin : feeWithMultiplier;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// includes value and nativeDrop
|
|
219
|
+
function _convertAndApplyPremiumToValue(
|
|
220
|
+
uint256 _value,
|
|
221
|
+
uint128 _ratio,
|
|
222
|
+
uint128 _denom,
|
|
223
|
+
uint16 _multiplierBps
|
|
224
|
+
) internal pure returns (uint256 fee) {
|
|
225
|
+
if (_value > 0) {
|
|
226
|
+
fee = (((_value * _ratio) / _denom) * _multiplierBps) / 10000;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function _isV1Eid(uint32 _eid) internal pure virtual returns (bool) {
|
|
231
|
+
// v1 eid is < 30000
|
|
232
|
+
return _eid < 30000;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function version() external pure returns (uint64 major, uint8 minor) {
|
|
236
|
+
return (1, 1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// send funds here to pay for price feed directly
|
|
240
|
+
receive() external payable {}
|
|
241
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
/// @dev simply a container of endpoint address and local eid
|
|
6
|
+
abstract contract MessageLibBase {
|
|
7
|
+
address internal immutable endpoint;
|
|
8
|
+
uint32 internal immutable localEid;
|
|
9
|
+
|
|
10
|
+
error LZ_MessageLib_OnlyEndpoint();
|
|
11
|
+
|
|
12
|
+
modifier onlyEndpoint() {
|
|
13
|
+
if (endpoint != msg.sender) revert LZ_MessageLib_OnlyEndpoint();
|
|
14
|
+
_;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
constructor(address _endpoint, uint32 _localEid) {
|
|
18
|
+
endpoint = _endpoint;
|
|
19
|
+
localEid = _localEid;
|
|
20
|
+
}
|
|
21
|
+
}
|