@layerzerolabs/lz-evm-messagelib-v2 2.0.2
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 +1156 -0
- package/artifacts/contracts/ExecutorFeeLib.sol/ExecutorFeeLib.json +336 -0
- package/artifacts/contracts/MessageLibBase.sol/MessageLibBase.json +16 -0
- package/artifacts/contracts/PriceFeed.sol/PriceFeed.json +650 -0
- package/artifacts/contracts/ReceiveLibBaseE2.sol/ReceiveLibBaseE2.json +154 -0
- package/artifacts/contracts/SendLibBase.sol/SendLibBase.json +381 -0
- package/artifacts/contracts/SendLibBaseE2.sol/SendLibBaseE2.json +819 -0
- package/artifacts/contracts/Treasury.sol/Treasury.json +309 -0
- package/artifacts/contracts/Worker.sol/Worker.json +579 -0
- package/artifacts/contracts/interfaces/IExecutor.sol/IExecutor.json +429 -0
- package/artifacts/contracts/interfaces/IExecutorFeeLib.sol/IExecutorFeeLib.json +210 -0
- package/artifacts/contracts/interfaces/ILayerZeroExecutor.sol/ILayerZeroExecutor.json +79 -0
- package/artifacts/contracts/interfaces/ILayerZeroPriceFeed.sol/ILayerZeroPriceFeed.json +222 -0
- package/artifacts/contracts/interfaces/ILayerZeroTreasury.sol/ILayerZeroTreasury.json +79 -0
- package/artifacts/contracts/interfaces/IWorker.sol/IWorker.json +221 -0
- package/artifacts/contracts/libs/SafeCall.sol/SafeCall.json +10 -0
- package/artifacts/contracts/uln/LzExecutor.sol/LzExecutor.json +256 -0
- package/artifacts/contracts/uln/ReceiveUlnBase.sol/ReceiveUlnBase.json +472 -0
- package/artifacts/contracts/uln/SendUlnBase.sol/SendUlnBase.json +412 -0
- package/artifacts/contracts/uln/UlnBase.sol/UlnBase.json +387 -0
- package/artifacts/contracts/uln/dvn/DVN.sol/DVN.json +1370 -0
- package/artifacts/contracts/uln/dvn/DVNFeeLib.sol/DVNFeeLib.json +300 -0
- package/artifacts/contracts/uln/dvn/MultiSig.sol/MultiSig.json +164 -0
- package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol/CCIPDVNAdapter.json +742 -0
- package/artifacts/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol/CCIPDVNAdapterFeeLib.json +50 -0
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterBase.sol/DVNAdapterBase.json +463 -0
- package/artifacts/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol/DVNAdapterFeeLibBase.json +50 -0
- package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol/AxelarDVNAdapter.json +804 -0
- package/artifacts/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol/AxelarDVNAdapterFeeLib.json +50 -0
- package/artifacts/contracts/uln/interfaces/IDVN.sol/IDVN.json +370 -0
- package/artifacts/contracts/uln/interfaces/IDVNAdapterFeeLib.sol/IDVNAdapterFeeLib.json +50 -0
- package/artifacts/contracts/uln/interfaces/IDVNFeeLib.sol/IDVNFeeLib.json +178 -0
- package/artifacts/contracts/uln/interfaces/ILayerZeroDVN.sol/ILayerZeroDVN.json +96 -0
- package/artifacts/contracts/uln/interfaces/IReceiveUlnE2.sol/IReceiveUlnE2.json +76 -0
- package/artifacts/contracts/uln/libs/DVNOptions.sol/DVNOptions.json +27 -0
- package/artifacts/contracts/uln/libs/UlnOptions.sol/UlnOptions.json +54 -0
- package/artifacts/contracts/uln/uln301/AddressSizeConfig.sol/AddressSizeConfig.json +129 -0
- package/artifacts/contracts/uln/uln301/ReceiveLibBaseE1.sol/ILayerZeroReceiveLibrary.json +68 -0
- package/artifacts/contracts/uln/uln301/ReceiveLibBaseE1.sol/ReceiveLibBaseE1.json +416 -0
- package/artifacts/contracts/uln/uln301/ReceiveUln301.sol/ReceiveUln301.json +969 -0
- package/artifacts/contracts/uln/uln301/SendLibBaseE1.sol/SendLibBaseE1.json +804 -0
- package/artifacts/contracts/uln/uln301/SendUln301.sol/SendUln301.json +1278 -0
- package/artifacts/contracts/uln/uln301/TreasuryFeeHandler.sol/TreasuryFeeHandler.json +94 -0
- package/artifacts/contracts/uln/uln301/interfaces/IMessageLibE1.sol/IMessageLibE1.json +247 -0
- package/artifacts/contracts/uln/uln301/interfaces/INonceContract.sol/INonceContract.json +40 -0
- package/artifacts/contracts/uln/uln301/interfaces/ITreasuryFeeHandler.sol/ITreasuryFeeHandler.json +44 -0
- package/artifacts/contracts/uln/uln301/interfaces/IUltraLightNode301.sol/IUltraLightNode301.json +29 -0
- package/artifacts/contracts/uln/uln301/mocks/NonceContractMock.sol/NonceContractMock.json +93 -0
- package/artifacts/contracts/uln/uln302/ReceiveUln302.sol/ReceiveUln302.json +702 -0
- package/artifacts/contracts/uln/uln302/SendUln302.sol/SendUln302.json +1259 -0
- package/artifacts/contracts/upgradeable/WorkerUpgradeable.sol/WorkerUpgradeable.json +592 -0
- package/artifacts/contracts/upgradeable/proxy/ProxyAdmin.sol/ProxyAdmin.json +181 -0
- package/artifacts/contracts/upgradeable/proxy/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +160 -0
- package/contracts/Executor.sol +162 -0
- package/contracts/ExecutorFeeLib.sol +190 -0
- package/contracts/MessageLibBase.sol +21 -0
- package/contracts/PriceFeed.sol +257 -0
- package/contracts/ReceiveLibBaseE2.sol +54 -0
- package/contracts/SendLibBase.sol +258 -0
- package/contracts/SendLibBaseE2.sol +140 -0
- package/contracts/Treasury.sol +74 -0
- package/contracts/Worker.sol +167 -0
- package/contracts/interfaces/IExecutor.sol +44 -0
- package/contracts/interfaces/IExecutorFeeLib.sol +32 -0
- package/contracts/interfaces/ILayerZeroExecutor.sol +29 -0
- package/contracts/interfaces/ILayerZeroPriceFeed.sol +61 -0
- package/contracts/interfaces/ILayerZeroTreasury.sol +19 -0
- package/contracts/interfaces/IWorker.sol +29 -0
- package/contracts/libs/SafeCall.sol +123 -0
- package/contracts/uln/LzExecutor.sol +96 -0
- package/contracts/uln/ReceiveUlnBase.sol +118 -0
- package/contracts/uln/SendUlnBase.sol +129 -0
- package/contracts/uln/UlnBase.sol +195 -0
- package/contracts/uln/dvn/DVN.sol +349 -0
- package/contracts/uln/dvn/DVNFeeLib.sol +141 -0
- package/contracts/uln/dvn/MultiSig.sol +104 -0
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapter.sol +152 -0
- package/contracts/uln/dvn/adapters/CCIP/CCIPDVNAdapterFeeLib.sol +7 -0
- package/contracts/uln/dvn/adapters/DVNAdapterBase.sol +162 -0
- package/contracts/uln/dvn/adapters/DVNAdapterFeeLibBase.sol +20 -0
- package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapter.sol +156 -0
- package/contracts/uln/dvn/adapters/axelar/AxelarDVNAdapterFeeLib.sol +7 -0
- package/contracts/uln/interfaces/IDVN.sol +25 -0
- package/contracts/uln/interfaces/IDVNAdapterFeeLib.sol +13 -0
- package/contracts/uln/interfaces/IDVNFeeLib.sol +30 -0
- package/contracts/uln/interfaces/ILayerZeroDVN.sol +34 -0
- package/contracts/uln/interfaces/IReceiveUlnE2.sol +18 -0
- package/contracts/uln/libs/DVNOptions.sol +181 -0
- package/contracts/uln/libs/UlnOptions.sol +176 -0
- package/contracts/uln/uln301/AddressSizeConfig.sol +22 -0
- package/contracts/uln/uln301/ReceiveLibBaseE1.sol +103 -0
- package/contracts/uln/uln301/ReceiveUln301.sol +120 -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 +108 -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/package.json +51 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
import { IExecutor } from "./IExecutor.sol";
|
|
6
|
+
|
|
7
|
+
interface IExecutorFeeLib {
|
|
8
|
+
struct FeeParams {
|
|
9
|
+
address priceFeed;
|
|
10
|
+
uint32 dstEid;
|
|
11
|
+
address sender;
|
|
12
|
+
uint256 calldataSize;
|
|
13
|
+
uint16 defaultMultiplierBps;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
error NoOptions();
|
|
17
|
+
error NativeAmountExceedsCap(uint256 amount, uint256 cap);
|
|
18
|
+
error UnsupportedOptionType(uint8 optionType);
|
|
19
|
+
error InvalidExecutorOptions(uint256 cursor);
|
|
20
|
+
|
|
21
|
+
function getFeeOnSend(
|
|
22
|
+
FeeParams calldata _params,
|
|
23
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
24
|
+
bytes calldata _options
|
|
25
|
+
) external returns (uint256 fee);
|
|
26
|
+
|
|
27
|
+
function getFee(
|
|
28
|
+
FeeParams calldata _params,
|
|
29
|
+
IExecutor.DstConfig calldata _dstConfig,
|
|
30
|
+
bytes calldata _options
|
|
31
|
+
) external view returns (uint256 fee);
|
|
32
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
interface ILayerZeroExecutor {
|
|
6
|
+
// @notice query price and assign jobs at the same time
|
|
7
|
+
// @param _dstEid - the destination endpoint identifier
|
|
8
|
+
// @param _sender - the source sending contract address. executors may apply price discrimination to senders
|
|
9
|
+
// @param _calldataSize - dynamic data size of message + caller params
|
|
10
|
+
// @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
|
|
11
|
+
function assignJob(
|
|
12
|
+
uint32 _dstEid,
|
|
13
|
+
address _sender,
|
|
14
|
+
uint256 _calldataSize,
|
|
15
|
+
bytes calldata _options
|
|
16
|
+
) external returns (uint256 price);
|
|
17
|
+
|
|
18
|
+
// @notice query the executor price for relaying the payload and its proof to the destination chain
|
|
19
|
+
// @param _dstEid - the destination endpoint identifier
|
|
20
|
+
// @param _sender - the source sending contract address. executors may apply price discrimination to senders
|
|
21
|
+
// @param _calldataSize - dynamic data size of message + caller params
|
|
22
|
+
// @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
|
|
23
|
+
function getFee(
|
|
24
|
+
uint32 _dstEid,
|
|
25
|
+
address _sender,
|
|
26
|
+
uint256 _calldataSize,
|
|
27
|
+
bytes calldata _options
|
|
28
|
+
) external view returns (uint256 price);
|
|
29
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
interface ILayerZeroPriceFeed {
|
|
6
|
+
/**
|
|
7
|
+
* @dev
|
|
8
|
+
* priceRatio: (USD price of 1 unit of remote native token in unit of local native token) * PRICE_RATIO_DENOMINATOR
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
struct Price {
|
|
12
|
+
uint128 priceRatio; // float value * 10 ^ 20, decimal awared. for aptos to evm, the basis would be (10^18 / 10^8) * 10 ^20 = 10 ^ 30.
|
|
13
|
+
uint64 gasPriceInUnit; // for evm, it is in wei, for aptos, it is in octas.
|
|
14
|
+
uint32 gasPerByte;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
struct UpdatePrice {
|
|
18
|
+
uint32 eid;
|
|
19
|
+
Price price;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @dev
|
|
24
|
+
* ArbGasInfo.go:GetPricesInArbGas
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
struct ArbitrumPriceExt {
|
|
28
|
+
uint64 gasPerL2Tx; // L2 overhead
|
|
29
|
+
uint32 gasPerL1CallDataByte;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
struct UpdatePriceExt {
|
|
33
|
+
uint32 eid;
|
|
34
|
+
Price price;
|
|
35
|
+
ArbitrumPriceExt extend;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
error OnlyPriceUpdater();
|
|
39
|
+
error InsufficientFee(uint256 provided, uint256 required);
|
|
40
|
+
error UnknownL2Eid(uint32 l2Eid);
|
|
41
|
+
|
|
42
|
+
function nativeTokenPriceUSD() external view returns (uint128);
|
|
43
|
+
|
|
44
|
+
function getFee(uint32 _dstEid, uint256 _callDataSize, uint256 _gas) external view returns (uint256);
|
|
45
|
+
|
|
46
|
+
function getPrice(uint32 _dstEid) external view returns (Price memory);
|
|
47
|
+
|
|
48
|
+
function getPriceRatioDenominator() external view returns (uint128);
|
|
49
|
+
|
|
50
|
+
function estimateFeeByEid(
|
|
51
|
+
uint32 _dstEid,
|
|
52
|
+
uint256 _callDataSize,
|
|
53
|
+
uint256 _gas
|
|
54
|
+
) external view returns (uint256 fee, uint128 priceRatio, uint128 priceRatioDenominator, uint128 nativePriceUSD);
|
|
55
|
+
|
|
56
|
+
function estimateFeeOnSend(
|
|
57
|
+
uint32 _dstEid,
|
|
58
|
+
uint256 _callDataSize,
|
|
59
|
+
uint256 _gas
|
|
60
|
+
) external payable returns (uint256 fee, uint128 priceRatio, uint128 priceRatioDenominator, uint128 nativePriceUSD);
|
|
61
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
interface ILayerZeroTreasury {
|
|
6
|
+
function getFee(
|
|
7
|
+
address _sender,
|
|
8
|
+
uint32 _dstEid,
|
|
9
|
+
uint256 _totalNativeFee,
|
|
10
|
+
bool _payInLzToken
|
|
11
|
+
) external view returns (uint256 fee);
|
|
12
|
+
|
|
13
|
+
function payFee(
|
|
14
|
+
address _sender,
|
|
15
|
+
uint32 _dstEid,
|
|
16
|
+
uint256 _totalNativeFee,
|
|
17
|
+
bool _payInLzToken
|
|
18
|
+
) external payable returns (uint256 fee);
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity >=0.8.0;
|
|
4
|
+
|
|
5
|
+
interface IWorker {
|
|
6
|
+
event SetWorkerLib(address workerLib);
|
|
7
|
+
event SetPriceFeed(address priceFeed);
|
|
8
|
+
event SetDefaultMultiplierBps(uint16 multiplierBps);
|
|
9
|
+
event SetSupportedOptionTypes(uint32 dstEid, uint8[] optionTypes);
|
|
10
|
+
event Withdraw(address lib, address to, uint256 amount);
|
|
11
|
+
|
|
12
|
+
error NotAllowed();
|
|
13
|
+
error OnlyMessageLib();
|
|
14
|
+
error RoleRenouncingDisabled();
|
|
15
|
+
|
|
16
|
+
function setPriceFeed(address _priceFeed) external;
|
|
17
|
+
|
|
18
|
+
function priceFeed() external view returns (address);
|
|
19
|
+
|
|
20
|
+
function setDefaultMultiplierBps(uint16 _multiplierBps) external;
|
|
21
|
+
|
|
22
|
+
function defaultMultiplierBps() external view returns (uint16);
|
|
23
|
+
|
|
24
|
+
function withdrawFee(address _lib, address _to, uint256 _amount) external;
|
|
25
|
+
|
|
26
|
+
function setSupportedOptionTypes(uint32 _eid, uint8[] calldata _optionTypes) external;
|
|
27
|
+
|
|
28
|
+
function getSupportedOptionTypes(uint32 _eid) external view returns (uint8[] memory);
|
|
29
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.22;
|
|
4
|
+
|
|
5
|
+
/// @dev copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
|
|
6
|
+
library SafeCall {
|
|
7
|
+
/// @notice calls a contract with a specified gas limit and value and captures the return data
|
|
8
|
+
/// @param _target The address to call
|
|
9
|
+
/// @param _gas The amount of gas to forward to the remote contract
|
|
10
|
+
/// @param _value The value in wei to send to the remote contract
|
|
11
|
+
/// to memory.
|
|
12
|
+
/// @param _maxCopy The maximum number of bytes of returndata to copy
|
|
13
|
+
/// to memory.
|
|
14
|
+
/// @param _calldata The data to send to the remote contract
|
|
15
|
+
/// @return success and returndata, as `.call()`. Returndata is capped to
|
|
16
|
+
/// `_maxCopy` bytes.
|
|
17
|
+
function safeCall(
|
|
18
|
+
address _target,
|
|
19
|
+
uint256 _gas,
|
|
20
|
+
uint256 _value,
|
|
21
|
+
uint16 _maxCopy,
|
|
22
|
+
bytes memory _calldata
|
|
23
|
+
) internal returns (bool, bytes memory) {
|
|
24
|
+
// check that target has code
|
|
25
|
+
uint size;
|
|
26
|
+
assembly {
|
|
27
|
+
size := extcodesize(_target)
|
|
28
|
+
}
|
|
29
|
+
if (size == 0) {
|
|
30
|
+
return (false, new bytes(0));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// set up for assembly call
|
|
34
|
+
uint256 _toCopy;
|
|
35
|
+
bool _success;
|
|
36
|
+
bytes memory _returnData = new bytes(_maxCopy);
|
|
37
|
+
// dispatch message to recipient
|
|
38
|
+
// by assembly calling "handle" function
|
|
39
|
+
// we call via assembly to avoid memcopying a very large returndata
|
|
40
|
+
// returned by a malicious contract
|
|
41
|
+
assembly {
|
|
42
|
+
_success := call(
|
|
43
|
+
_gas, // gas
|
|
44
|
+
_target, // recipient
|
|
45
|
+
_value, // ether value
|
|
46
|
+
add(_calldata, 0x20), // inloc
|
|
47
|
+
mload(_calldata), // inlen
|
|
48
|
+
0, // outloc
|
|
49
|
+
0 // outlen
|
|
50
|
+
)
|
|
51
|
+
// limit our copy to 100 bytes
|
|
52
|
+
_toCopy := returndatasize()
|
|
53
|
+
if gt(_toCopy, _maxCopy) {
|
|
54
|
+
_toCopy := _maxCopy
|
|
55
|
+
}
|
|
56
|
+
// Store the length of the copied bytes
|
|
57
|
+
mstore(_returnData, _toCopy)
|
|
58
|
+
// copy the bytes from returndata[0:_toCopy]
|
|
59
|
+
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
|
|
60
|
+
}
|
|
61
|
+
return (_success, _returnData);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// @notice Use when you _really_ really _really_ don't trust the called
|
|
65
|
+
/// contract. This prevents the called contract from causing reversion of
|
|
66
|
+
/// the caller in as many ways as we can.
|
|
67
|
+
/// @dev The main difference between this and a solidity low-level call is
|
|
68
|
+
/// that we limit the number of bytes that the callee can cause to be
|
|
69
|
+
/// copied to caller memory. This prevents stupid things like malicious
|
|
70
|
+
/// contracts returning 10,000,000 bytes causing a local OOG when copying
|
|
71
|
+
/// to memory.
|
|
72
|
+
/// @param _target The address to call
|
|
73
|
+
/// @param _gas The amount of gas to forward to the remote contract
|
|
74
|
+
/// @param _maxCopy The maximum number of bytes of returndata to copy
|
|
75
|
+
/// to memory.
|
|
76
|
+
/// @param _calldata The data to send to the remote contract
|
|
77
|
+
/// @return success and returndata, as `.call()`. Returndata is capped to
|
|
78
|
+
/// `_maxCopy` bytes.
|
|
79
|
+
function safeStaticCall(
|
|
80
|
+
address _target,
|
|
81
|
+
uint256 _gas,
|
|
82
|
+
uint16 _maxCopy,
|
|
83
|
+
bytes memory _calldata
|
|
84
|
+
) internal view returns (bool, bytes memory) {
|
|
85
|
+
// check that target has code
|
|
86
|
+
uint size;
|
|
87
|
+
assembly {
|
|
88
|
+
size := extcodesize(_target)
|
|
89
|
+
}
|
|
90
|
+
if (size == 0) {
|
|
91
|
+
return (false, new bytes(0));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// set up for assembly call
|
|
95
|
+
uint256 _toCopy;
|
|
96
|
+
bool _success;
|
|
97
|
+
bytes memory _returnData = new bytes(_maxCopy);
|
|
98
|
+
// dispatch message to recipient
|
|
99
|
+
// by assembly calling "handle" function
|
|
100
|
+
// we call via assembly to avoid memcopying a very large returndata
|
|
101
|
+
// returned by a malicious contract
|
|
102
|
+
assembly {
|
|
103
|
+
_success := staticcall(
|
|
104
|
+
_gas, // gas
|
|
105
|
+
_target, // recipient
|
|
106
|
+
add(_calldata, 0x20), // inloc
|
|
107
|
+
mload(_calldata), // inlen
|
|
108
|
+
0, // outloc
|
|
109
|
+
0 // outlen
|
|
110
|
+
)
|
|
111
|
+
// limit our copy to 256 bytes
|
|
112
|
+
_toCopy := returndatasize()
|
|
113
|
+
if gt(_toCopy, _maxCopy) {
|
|
114
|
+
_toCopy := _maxCopy
|
|
115
|
+
}
|
|
116
|
+
// Store the length of the copied bytes
|
|
117
|
+
mstore(_returnData, _toCopy)
|
|
118
|
+
// copy the bytes from returndata[0:_toCopy]
|
|
119
|
+
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
|
|
120
|
+
}
|
|
121
|
+
return (_success, _returnData);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity 0.8.22;
|
|
4
|
+
|
|
5
|
+
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
|
6
|
+
|
|
7
|
+
import { IReceiveUlnE2 } from "./interfaces/IReceiveUlnE2.sol";
|
|
8
|
+
import { ILayerZeroEndpointV2, ExecutionState, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
|
|
9
|
+
import { Transfer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
|
|
10
|
+
|
|
11
|
+
import { VerificationState } from "./ReceiveUlnBase.sol";
|
|
12
|
+
|
|
13
|
+
struct LzReceiveParam {
|
|
14
|
+
Origin origin;
|
|
15
|
+
address receiver;
|
|
16
|
+
bytes32 guid;
|
|
17
|
+
bytes message;
|
|
18
|
+
bytes extraData;
|
|
19
|
+
uint256 gas;
|
|
20
|
+
uint256 value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
struct NativeDropParam {
|
|
24
|
+
address _receiver;
|
|
25
|
+
uint256 _amount;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
contract LzExecutor is Ownable {
|
|
29
|
+
address public immutable receiveUln302;
|
|
30
|
+
ILayerZeroEndpointV2 public immutable endpoint;
|
|
31
|
+
uint32 public immutable localEid;
|
|
32
|
+
|
|
33
|
+
error Executed();
|
|
34
|
+
error Verifying();
|
|
35
|
+
|
|
36
|
+
constructor(address _receiveUln302, address _endpoint) {
|
|
37
|
+
receiveUln302 = _receiveUln302;
|
|
38
|
+
endpoint = ILayerZeroEndpointV2(_endpoint);
|
|
39
|
+
localEid = endpoint.eid();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// @notice process for commit and execute
|
|
43
|
+
/// 1. check if executable, revert if executed, execute if executable
|
|
44
|
+
/// 2. check if verifiable, revert if verifying, commit if verifiable
|
|
45
|
+
/// 3. native drop
|
|
46
|
+
/// 4. try execute, will revert if not executable
|
|
47
|
+
function commitAndExecute(
|
|
48
|
+
address _receiveLib,
|
|
49
|
+
LzReceiveParam calldata _lzReceiveParam,
|
|
50
|
+
NativeDropParam calldata _nativeDropParam
|
|
51
|
+
) external payable {
|
|
52
|
+
/// 1. check if executable, revert if executed
|
|
53
|
+
ExecutionState executionState = endpoint.executable(_lzReceiveParam.origin, _lzReceiveParam.receiver);
|
|
54
|
+
if (executionState == ExecutionState.Executed) revert Executed();
|
|
55
|
+
|
|
56
|
+
/// 2. if not executable, check if verifiable, revert if verifying, commit if verifiable
|
|
57
|
+
if (executionState != ExecutionState.Executable) {
|
|
58
|
+
address receiveLib = receiveUln302 == address(0x0) ? _receiveLib : address(receiveUln302);
|
|
59
|
+
bytes memory packetHeader = abi.encodePacked(
|
|
60
|
+
uint8(1), // packet version 1
|
|
61
|
+
_lzReceiveParam.origin.nonce,
|
|
62
|
+
_lzReceiveParam.origin.srcEid,
|
|
63
|
+
_lzReceiveParam.origin.sender,
|
|
64
|
+
localEid,
|
|
65
|
+
bytes32(uint256(uint160(_lzReceiveParam.receiver)))
|
|
66
|
+
);
|
|
67
|
+
bytes32 payloadHash = keccak256(abi.encodePacked(_lzReceiveParam.guid, _lzReceiveParam.message));
|
|
68
|
+
|
|
69
|
+
VerificationState verificationState = IReceiveUlnE2(receiveLib).verifiable(packetHeader, payloadHash);
|
|
70
|
+
if (verificationState == VerificationState.Verifiable) {
|
|
71
|
+
// verification required
|
|
72
|
+
IReceiveUlnE2(receiveLib).commitVerification(packetHeader, payloadHash);
|
|
73
|
+
} else if (verificationState == VerificationState.Verifying) {
|
|
74
|
+
revert Verifying();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// 3. native drop
|
|
79
|
+
if (_nativeDropParam._amount > 0 && _nativeDropParam._receiver != address(0x0)) {
|
|
80
|
+
Transfer.native(_nativeDropParam._receiver, _nativeDropParam._amount);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// 4. try execute, will revert if not executable
|
|
84
|
+
endpoint.lzReceive{ gas: _lzReceiveParam.gas, value: _lzReceiveParam.value }(
|
|
85
|
+
_lzReceiveParam.origin,
|
|
86
|
+
_lzReceiveParam.receiver,
|
|
87
|
+
_lzReceiveParam.guid,
|
|
88
|
+
_lzReceiveParam.message,
|
|
89
|
+
_lzReceiveParam.extraData
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function withdrawNative(address _to, uint256 _amount) external onlyOwner {
|
|
94
|
+
Transfer.native(_to, _amount);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.22;
|
|
4
|
+
|
|
5
|
+
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
|
|
6
|
+
|
|
7
|
+
import { UlnBase, UlnConfig } from "./UlnBase.sol";
|
|
8
|
+
|
|
9
|
+
enum VerificationState {
|
|
10
|
+
Verifying,
|
|
11
|
+
Verifiable,
|
|
12
|
+
Verified
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
struct Verification {
|
|
16
|
+
bool submitted;
|
|
17
|
+
uint64 confirmations;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// @dev includes the utility functions for checking ULN states and logics
|
|
21
|
+
abstract contract ReceiveUlnBase is UlnBase {
|
|
22
|
+
using PacketV1Codec for bytes;
|
|
23
|
+
|
|
24
|
+
mapping(bytes32 headerHash => mapping(bytes32 payloadHash => mapping(address dvn => Verification)))
|
|
25
|
+
public hashLookup;
|
|
26
|
+
|
|
27
|
+
event PayloadVerified(address dvn, bytes header, uint256 confirmations, bytes32 proofHash);
|
|
28
|
+
|
|
29
|
+
error InvalidPacketHeader();
|
|
30
|
+
error InvalidPacketVersion();
|
|
31
|
+
error InvalidEid();
|
|
32
|
+
error Verifying();
|
|
33
|
+
|
|
34
|
+
// ============================ Internal ===================================
|
|
35
|
+
/// @dev per DVN signing function
|
|
36
|
+
function _verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) internal {
|
|
37
|
+
hashLookup[keccak256(_packetHeader)][_payloadHash][msg.sender] = Verification(true, _confirmations);
|
|
38
|
+
emit PayloadVerified(msg.sender, _packetHeader, _confirmations, _payloadHash);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function _verified(
|
|
42
|
+
address _dvn,
|
|
43
|
+
bytes32 _headerHash,
|
|
44
|
+
bytes32 _payloadHash,
|
|
45
|
+
uint64 _requiredConfirmation
|
|
46
|
+
) internal view returns (bool verified) {
|
|
47
|
+
Verification memory verification = hashLookup[_headerHash][_payloadHash][_dvn];
|
|
48
|
+
// return true if the dvn has signed enough confirmations
|
|
49
|
+
verified = verification.submitted && verification.confirmations >= _requiredConfirmation;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function _verifyAndReclaimStorage(UlnConfig memory _config, bytes32 _headerHash, bytes32 _payloadHash) internal {
|
|
53
|
+
if (!_checkVerifiable(_config, _headerHash, _payloadHash)) {
|
|
54
|
+
revert Verifying();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// iterate the required DVNs
|
|
58
|
+
if (_config.requiredDVNCount > 0) {
|
|
59
|
+
for (uint8 i = 0; i < _config.requiredDVNCount; ++i) {
|
|
60
|
+
delete hashLookup[_headerHash][_payloadHash][_config.requiredDVNs[i]];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// iterate the optional DVNs
|
|
65
|
+
if (_config.optionalDVNCount > 0) {
|
|
66
|
+
for (uint8 i = 0; i < _config.optionalDVNCount; ++i) {
|
|
67
|
+
delete hashLookup[_headerHash][_payloadHash][_config.optionalDVNs[i]];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function _assertHeader(bytes calldata _packetHeader, uint32 _localEid) internal pure {
|
|
73
|
+
// assert packet header is of right size 81
|
|
74
|
+
if (_packetHeader.length != 81) revert InvalidPacketHeader();
|
|
75
|
+
// assert packet header version is the same as ULN
|
|
76
|
+
if (_packetHeader.version() != PacketV1Codec.PACKET_VERSION) revert InvalidPacketVersion();
|
|
77
|
+
// assert the packet is for this endpoint
|
|
78
|
+
if (_packetHeader.dstEid() != _localEid) revert InvalidEid();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// @dev for verifiable view function
|
|
82
|
+
/// @dev checks if this verification is ready to be committed to the endpoint
|
|
83
|
+
function _checkVerifiable(
|
|
84
|
+
UlnConfig memory _config,
|
|
85
|
+
bytes32 _headerHash,
|
|
86
|
+
bytes32 _payloadHash
|
|
87
|
+
) internal view returns (bool) {
|
|
88
|
+
// iterate the required DVNs
|
|
89
|
+
if (_config.requiredDVNCount > 0) {
|
|
90
|
+
for (uint8 i = 0; i < _config.requiredDVNCount; ++i) {
|
|
91
|
+
if (!_verified(_config.requiredDVNs[i], _headerHash, _payloadHash, _config.confirmations)) {
|
|
92
|
+
// return if any of the required DVNs haven't signed
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (_config.optionalDVNCount == 0) {
|
|
97
|
+
// returns early if all required DVNs have signed and there are no optional DVNs
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// then it must require optional validations
|
|
103
|
+
uint8 threshold = _config.optionalDVNThreshold;
|
|
104
|
+
for (uint8 i = 0; i < _config.optionalDVNCount; ++i) {
|
|
105
|
+
if (_verified(_config.optionalDVNs[i], _headerHash, _payloadHash, _config.confirmations)) {
|
|
106
|
+
// increment the optional count if the optional DVN has signed
|
|
107
|
+
threshold--;
|
|
108
|
+
if (threshold == 0) {
|
|
109
|
+
// early return if the optional threshold has hit
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// return false as a catch-all
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LZBL-1.2
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.22;
|
|
4
|
+
|
|
5
|
+
import { Packet } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
|
|
6
|
+
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
|
|
7
|
+
|
|
8
|
+
import { ILayerZeroDVN } from "./interfaces/ILayerZeroDVN.sol";
|
|
9
|
+
import { DVNOptions } from "./libs/DVNOptions.sol";
|
|
10
|
+
import { UlnOptions } from "./libs/UlnOptions.sol";
|
|
11
|
+
import { WorkerOptions } from "../SendLibBase.sol";
|
|
12
|
+
import { UlnConfig, UlnBase } from "./UlnBase.sol";
|
|
13
|
+
|
|
14
|
+
/// @dev includes the utility functions for checking ULN states and logics
|
|
15
|
+
abstract contract SendUlnBase is UlnBase {
|
|
16
|
+
event DVNFeePaid(address[] requiredDVNs, address[] optionalDVNs, uint256[] fees);
|
|
17
|
+
|
|
18
|
+
function _splitUlnOptions(bytes calldata _options) internal pure returns (bytes memory, WorkerOptions[] memory) {
|
|
19
|
+
(bytes memory executorOpts, bytes memory dvnOpts) = UlnOptions.decode(_options);
|
|
20
|
+
|
|
21
|
+
if (dvnOpts.length == 0) {
|
|
22
|
+
return (executorOpts, new WorkerOptions[](0));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
WorkerOptions[] memory workerOpts = new WorkerOptions[](1);
|
|
26
|
+
workerOpts[0] = WorkerOptions(DVNOptions.WORKER_ID, dvnOpts);
|
|
27
|
+
return (executorOpts, workerOpts);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// ---------- pay and assign jobs ----------
|
|
31
|
+
|
|
32
|
+
function _payDVNs(
|
|
33
|
+
mapping(address => uint256) storage _fees,
|
|
34
|
+
Packet memory _packet,
|
|
35
|
+
WorkerOptions[] memory _options
|
|
36
|
+
) internal returns (uint256 totalFee, bytes memory encodedPacket) {
|
|
37
|
+
bytes memory packetHeader = PacketV1Codec.encodePacketHeader(_packet);
|
|
38
|
+
bytes memory payload = PacketV1Codec.encodePayload(_packet);
|
|
39
|
+
bytes32 payloadHash = keccak256(payload);
|
|
40
|
+
uint32 dstEid = _packet.dstEid;
|
|
41
|
+
address sender = _packet.sender;
|
|
42
|
+
UlnConfig memory config = getUlnConfig(sender, dstEid);
|
|
43
|
+
|
|
44
|
+
// if options is not empty, it must be dvn options
|
|
45
|
+
bytes memory dvnOptions = _options.length == 0 ? bytes("") : _options[0].options;
|
|
46
|
+
uint256[] memory dvnFees;
|
|
47
|
+
(totalFee, dvnFees) = _assignJobs(
|
|
48
|
+
_fees,
|
|
49
|
+
config,
|
|
50
|
+
ILayerZeroDVN.AssignJobParam(dstEid, packetHeader, payloadHash, config.confirmations, sender),
|
|
51
|
+
dvnOptions
|
|
52
|
+
);
|
|
53
|
+
encodedPacket = abi.encodePacked(packetHeader, payload);
|
|
54
|
+
|
|
55
|
+
emit DVNFeePaid(config.requiredDVNs, config.optionalDVNs, dvnFees);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _assignJobs(
|
|
59
|
+
mapping(address => uint256) storage _fees,
|
|
60
|
+
UlnConfig memory _ulnConfig,
|
|
61
|
+
ILayerZeroDVN.AssignJobParam memory _param,
|
|
62
|
+
bytes memory dvnOptions
|
|
63
|
+
) internal returns (uint256 totalFee, uint256[] memory dvnFees) {
|
|
64
|
+
(bytes[] memory optionsArray, uint8[] memory dvnIds) = DVNOptions.groupDVNOptionsByIdx(dvnOptions);
|
|
65
|
+
|
|
66
|
+
uint8 dvnsLength = _ulnConfig.requiredDVNCount + _ulnConfig.optionalDVNCount;
|
|
67
|
+
dvnFees = new uint256[](dvnsLength);
|
|
68
|
+
for (uint8 i = 0; i < dvnsLength; ++i) {
|
|
69
|
+
address dvn = i < _ulnConfig.requiredDVNCount
|
|
70
|
+
? _ulnConfig.requiredDVNs[i]
|
|
71
|
+
: _ulnConfig.optionalDVNs[i - _ulnConfig.requiredDVNCount];
|
|
72
|
+
|
|
73
|
+
bytes memory options = "";
|
|
74
|
+
for (uint256 j = 0; j < dvnIds.length; ++j) {
|
|
75
|
+
if (dvnIds[j] == i) {
|
|
76
|
+
options = optionsArray[j];
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
dvnFees[i] = ILayerZeroDVN(dvn).assignJob(_param, options);
|
|
82
|
+
if (dvnFees[i] > 0) {
|
|
83
|
+
_fees[dvn] += dvnFees[i];
|
|
84
|
+
totalFee += dvnFees[i];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// ---------- quote ----------
|
|
90
|
+
function _quoteDVNs(
|
|
91
|
+
address _sender,
|
|
92
|
+
uint32 _dstEid,
|
|
93
|
+
WorkerOptions[] memory _options
|
|
94
|
+
) internal view returns (uint256 totalFee) {
|
|
95
|
+
UlnConfig memory config = getUlnConfig(_sender, _dstEid);
|
|
96
|
+
|
|
97
|
+
// if options is not empty, it must be dvn options
|
|
98
|
+
bytes memory dvnOptions = _options.length == 0 ? bytes("") : _options[0].options;
|
|
99
|
+
(bytes[] memory optionsArray, uint8[] memory dvnIndices) = DVNOptions.groupDVNOptionsByIdx(dvnOptions);
|
|
100
|
+
|
|
101
|
+
totalFee = _getFees(config, _dstEid, _sender, optionsArray, dvnIndices);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function _getFees(
|
|
105
|
+
UlnConfig memory _config,
|
|
106
|
+
uint32 _dstEid,
|
|
107
|
+
address _sender,
|
|
108
|
+
bytes[] memory _optionsArray,
|
|
109
|
+
uint8[] memory _dvnIds
|
|
110
|
+
) internal view returns (uint256 totalFee) {
|
|
111
|
+
// here we merge 2 list of dvns into 1 to allocate the indexed dvn options to the right dvn
|
|
112
|
+
uint8 dvnsLength = _config.requiredDVNCount + _config.optionalDVNCount;
|
|
113
|
+
for (uint8 i = 0; i < dvnsLength; ++i) {
|
|
114
|
+
address dvn = i < _config.requiredDVNCount
|
|
115
|
+
? _config.requiredDVNs[i]
|
|
116
|
+
: _config.optionalDVNs[i - _config.requiredDVNCount];
|
|
117
|
+
|
|
118
|
+
bytes memory options = "";
|
|
119
|
+
// it is a double loop here. however, if the list is short, the cost is very acceptable.
|
|
120
|
+
for (uint256 j = 0; j < _dvnIds.length; ++j) {
|
|
121
|
+
if (_dvnIds[j] == i) {
|
|
122
|
+
options = _optionsArray[j];
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
totalFee += ILayerZeroDVN(dvn).getFee(_dstEid, _config.confirmations, _sender, options);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|