Transaction Hash:
Block:
15032011 at Jun-27-2022 02:10:45 AM +UTC
Transaction Fee:
0.004689836014397882 ETH
$9.01
Gas Used:
254,594 Gas / 18.420842653 Gwei
Emitted Events:
| 173 |
0xcc5ab3f04704620d6f20a0cf2e772d6a81f42c4b.0xb7f880c0b7389b5c679312288379e3323c95ab57d418f8dd6fb6913f91e54738( 0xb7f880c0b7389b5c679312288379e3323c95ab57d418f8dd6fb6913f91e54738, 0000000000000000000000000000000000000000000000000000000000000001, 000000000000000000000000000000000000000000000000000000000000000a, 000000000000000000000000cc5ab3f04704620d6f20a0cf2e772d6a81f42c4b, 00000000000000000000000046c0fe865545353311d61e247201a1de3ca0e62e, 00000000000000000000000043d2e0ef56369c8259e6e4423cf6e473bb94dc06, 0067616e64616c6674686562726f776e67786d786e6900124485aa2b07e80000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000016345785d8a0000, 000000000000000000000000000000000000000000000000015a63bbc199c000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 174 |
UltraLightNode.RelayerParams( chainId=10, nonce=3472, outboundProofType=1, adapterParams=0x )
|
| 175 |
UltraLightNode.Packet( chainId=10, payload=0x0000000000000D9089AEF982DE66FE6DF58ED0251E0841CCB2DA6E4AED2F78F4CEB26C2E40056FBA5468D8AA0E1054380067616E64616C6674686562726F776E67786D786E6900124485AA2B07E80000000000000000000000000000CC5AB3F04704620D6F20A0CF2E772D6A81F42C4B00000000000000000000000046C0FE865545353311D61E247201A1DE3CA0E62E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043D2E0EF56369C8259E6E4423CF6E473BB94DC06000000000000000000000000000000000000000000000000015A63BBC199C000 )
|
| 176 |
0x41c69c8ffb4049fc393ed68ec0ce66c37f8cf7a0.0xf5f7eeb9c1ffb10aced9d0a5354641e9bccdde560963d05f8d26ad4a460c89a2( 0xf5f7eeb9c1ffb10aced9d0a5354641e9bccdde560963d05f8d26ad4a460c89a2, 000000000000000000000000000000000000000000000000000000000000000a, 0000000000000000000000000000000000000000000000000000000000000001, 000000000000000000000000000000000000000000000000000000000000000f )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x43D2E0eF...3bB94Dc06 |
0.302865166099492409 Eth
Nonce: 10
|
0.191968805952877716 Eth
Nonce: 11
| 0.110896360146614693 | ||
| 0x5B19bd33...217a18C1C | (LayerZero: Ultra Light Node) | 32.411601677310962308 Eth | 32.416998654817237796 Eth | 0.005396977506275488 | |
| 0x66A71Dce...C225Cd675 | (LayerZero: Ethereum Endpoint) | ||||
| 0x89aeF982...cB2da6E4a | 3.904511246697029896 Eth | 3.905320793322971219 Eth | 0.000809546625941323 | ||
| 0xCABBaC11...9b0562bF4 | |||||
| 0xCC5Ab3F0...a81F42C4b | 390.991090356635951647 Eth | 391.091090356635951647 Eth | 0.1 | ||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 2,965.869233988938656116 Eth | 2,965.869743176938656116 Eth | 0.000509188 |
Execution Trace
ETH 0.106206524132216811
Hashflow: Bridge.0031b016( )
ETH 0.106206524132216811
0xcc5ab3f04704620d6f20a0cf2e772d6a81f42c4b.2068dd30( )ETH 0.106206524132216811
0xacfaaa9da11e66a8cc8af8e3d844673968fff63f.2068dd30( )-
0xd33d83aac02456839400140d3e4c9a80347ac2f8.STATICCALL( ) ETH 0.006206524132216811
0x89aef982de66fe6df58ed0251e0841ccb2da6e4a.0d199e1f( )-
0xd33d83aac02456839400140d3e4c9a80347ac2f8.STATICCALL( ) -
0xd33d83aac02456839400140d3e4c9a80347ac2f8.STATICCALL( ) -
0xd33d83aac02456839400140d3e4c9a80347ac2f8.STATICCALL( ) -
Null: 0x000...001.ebe250fc( ) 0xcabbac11782722450f436ad733b4f7b9b0562bf4.c7e94551( )-
0xd33d83aac02456839400140d3e4c9a80347ac2f8.STATICCALL( )
-
Endpoint.estimateFees( _dstChainId=10, _userApplication=0x89aeF982DE66Fe6df58ed0251E0841CcB2da6E4a, _payload=0x0067616E64616C6674686562726F776E67786D786E6900124485AA2B07E80000000000000000000000000000CC5AB3F04704620D6F20A0CF2E772D6A81F42C4B00000000000000000000000046C0FE865545353311D61E247201A1DE3CA0E62E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043D2E0EF56369C8259E6E4423CF6E473BB94DC06000000000000000000000000000000000000000000000000015A63BBC199C000, _payInZRO=False, _adapterParams=0x ) => ( nativeFee=5396977506275488, zroFee=0 )UltraLightNode.estimateFees( _chainId=10, _ua=0x89aeF982DE66Fe6df58ed0251E0841CcB2da6E4a, _payload=0x0067616E64616C6674686562726F776E67786D786E6900124485AA2B07E80000000000000000000000000000CC5AB3F04704620D6F20A0CF2E772D6A81F42C4B00000000000000000000000046C0FE865545353311D61E247201A1DE3CA0E62E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043D2E0EF56369C8259E6E4423CF6E473BB94DC06000000000000000000000000000000000000000000000000015A63BBC199C000, _payInZRO=False, _adapterParams=0x ) => ( nativeFee=5396977506275488, zroFee=0 )-
LayerZero: Relayer.e54a2215( ) -
0x41c69c8ffb4049fc393ed68ec0ce66c37f8cf7a0.0b4d5107( ) -
0x94fe59afaff2d0a8ea6e8158feb7c65410867a9b.5cbbbd75( )
-
ETH 0.005396977506275488
Endpoint.send( _dstChainId=10, _destination=0xED2F78F4CEB26C2E40056FBA5468D8AA0E105438, _payload=0x0067616E64616C6674686562726F776E67786D786E6900124485AA2B07E80000000000000000000000000000CC5AB3F04704620D6F20A0CF2E772D6A81F42C4B00000000000000000000000046C0FE865545353311D61E247201A1DE3CA0E62E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043D2E0EF56369C8259E6E4423CF6E473BB94DC06000000000000000000000000000000000000000000000000015A63BBC199C000, _refundAddress=0x43D2E0eF56369C8259e6e4423cF6E473bB94Dc06, _zroPaymentAddress=0x0000000000000000000000000000000000000000, _adapterParams=0x )ETH 0.005396977506275488
UltraLightNode.send( _ua=0x89aeF982DE66Fe6df58ed0251E0841CcB2da6E4a, _nonce=3472, _chainId=10, _destination=0xED2F78F4CEB26C2E40056FBA5468D8AA0E105438, _payload=0x0067616E64616C6674686562726F776E67786D786E6900124485AA2B07E80000000000000000000000000000CC5AB3F04704620D6F20A0CF2E772D6A81F42C4B00000000000000000000000046C0FE865545353311D61E247201A1DE3CA0E62E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043D2E0EF56369C8259E6E4423CF6E473BB94DC06000000000000000000000000000000000000000000000000015A63BBC199C000, _refundAddress=0x43D2E0eF56369C8259e6e4423cF6E473bB94Dc06, _zroPaymentAddress=0x0000000000000000000000000000000000000000, _adapterParams=0x )-
0x41c69c8ffb4049fc393ed68ec0ce66c37f8cf7a0.0b4d5107( ) -
LayerZero: Relayer.e54a2215( ) -
LayerZero: Relayer.3a5fb82a( ) -
0x94fe59afaff2d0a8ea6e8158feb7c65410867a9b.5cbbbd75( ) -
0x41c69c8ffb4049fc393ed68ec0ce66c37f8cf7a0.66530579( )
-
-
-
File 1 of 2: UltraLightNode
File 2 of 2: Endpoint
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@layerzerolabs/proof-evm/contracts/ILayerZeroValidationLibrary.sol";
import "./interfaces/ILayerZeroMessagingLibrary.sol";
import "./interfaces/ILayerZeroReceiver.sol";
import "./interfaces/ILayerZeroRelayer.sol";
import "./interfaces/ILayerZeroTreasury.sol";
import "./interfaces/ILayerZeroOracle.sol";
import "./interfaces/ILayerZeroUltraLightNodeV1.sol";
import "./interfaces/ILayerZeroEndpoint.sol";
contract UltraLightNode is ILayerZeroMessagingLibrary, ILayerZeroUltraLightNodeV1, ReentrancyGuard, Ownable {
using SafeERC20 for IERC20;
using SafeMath for uint;
struct BlockData {
uint confirmations;
bytes32 data;
}
// Application config
uint public constant CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION = 1;
uint public constant CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS = 2;
uint public constant CONFIG_TYPE_RELAYER = 3;
uint public constant CONFIG_TYPE_OUTBOUND_PROOF_TYPE = 4;
uint public constant CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS = 5;
uint public constant CONFIG_TYPE_ORACLE = 6;
struct ApplicationConfiguration {
uint16 inboundProofLibraryVersion;
uint64 inboundBlockConfirmations;
address relayer;
uint16 outboundProofType;
uint64 outboundBlockConfirmations;
address oracle;
}
// Token and Contracts
IERC20 public layerZeroToken;
ILayerZeroTreasury public treasuryContract;
// Fee management
uint public constant BP_DENOMINATOR = 10000;
// treasury and relayer share the protocol fee, either in native token or ZRO
uint8 public constant WITHDRAW_TYPE_TREASURY_PROTOCOL_FEES = 0;
uint8 public constant WITHDRAW_TYPE_ORACLE_QUOTED_FEES = 1; // quoted fee refers to the fee in block relaying
uint8 public constant WITHDRAW_TYPE_RELAYER_QUOTED_FEES = 2; //quoted fee refers the fee in msg relaying
mapping(address => uint) public oracleQuotedFees;
mapping(address => uint) public relayerQuotedFees;
uint public treasuryNativeFees;
uint public treasuryZROFees;
// User Application
mapping(address => mapping(uint16 => ApplicationConfiguration)) public appConfig; // app address => chainId => config
mapping(uint16 => ApplicationConfiguration) public defaultAppConfig; // default UA settings if no version specified
mapping(uint16 => mapping(uint16 => bytes)) public defaultAdapterParams;
// Validation
mapping(uint16 => mapping(uint16 => address)) public inboundProofLibrary; // chainId => library Id => inboundProofLibrary contract
mapping(uint16 => uint16) public maxInboundProofLibrary; // chainId => inboundProofLibrary
mapping(uint16 => mapping(uint16 => bool)) public supportedOutboundProof; // chainId => outboundProofType => enabled
mapping(uint16 => uint) public chainAddressSizeMap;
mapping(address => mapping(uint16 => mapping(bytes32 => BlockData))) public hashLookup;
mapping(uint16 => bytes32) public ulnLookup; // remote ulns
ILayerZeroEndpoint public immutable endpoint;
// Events
event AppConfigUpdated(address userApplication, uint configType, bytes newConfig);
event AddInboundProofLibraryForChain(uint16 chainId, address lib);
event EnableSupportedOutboundProof(uint16 chainId, uint16 proofType);
event HashReceived(uint16 srcChainId, address oracle, uint confirmations, bytes32 blockhash);
event Packet(uint16 chainId, bytes payload);
event RelayerParams(uint16 chainId, uint64 nonce, uint16 outboundProofType, bytes adapterParams);
event SetChainAddressSize(uint16 chainId, uint size);
event SetDefaultConfigForChainId(uint16 chainId, uint16 inboundProofLib, uint64 inboundBlockConfirm, address relayer, uint16 outboundProofType, uint16 outboundBlockConfirm, address oracle);
event SetDefaultAdapterParamsForChainId(uint16 chainId, uint16 proofType, bytes adapterParams);
event SetLayerZeroToken(address tokenAddress);
event SetRelayerFeeContract(address relayerFeeContract);
event SetRemoteUln(uint16 chainId, bytes32 uln);
event SetTreasury(address treasuryAddress);
event WithdrawZRO(address _msgSender, address _to, uint _amount);
event WithdrawNative(uint8 _type, address _owner, address _msgSender, address _to, uint _amount);
constructor(address _endpoint) {
require(_endpoint != address(0x0), "LayerZero: endpoint cannot be zero address");
endpoint = ILayerZeroEndpoint(_endpoint);
}
// only the endpoint can call SEND() and setConfig()
modifier onlyEndpoint() {
require(address(endpoint) == msg.sender, "LayerZero: only endpoint");
_;
}
//----------------------------------------------------------------------------------
// PROTOCOL
// This function completes delivery of a LayerZero message.
//
// In order to deliver the message, this function:
// (a) takes the _transactionProof submitted by UA's relayer, and
// (b) retrieve UA's validation library
// (c) takes the _blockData submitted by the UA's oracle given the their configuration (and blockConfirmations),
// (d) decodes using UA's validation library using (a) and (c)
// then, this functions asserts that
// (e) the payload originated from the known Ultra Light Node from source chain, and
// (f) the _dstAddress the specified destination contract
function validateTransactionProof(uint16 _srcChainId, address _dstAddress, uint _gasLimit, bytes32 _lookupHash, bytes calldata _transactionProof) external override {
// retrieve UA's configuration using the _dstAddress from arguments.
ApplicationConfiguration memory uaConfig = getAppConfig(_srcChainId, _dstAddress);
// (a) assert that the caller == UA's relayer
require(uaConfig.relayer == msg.sender, "LayerZero: invalid relayer");
LayerZeroPacket.Packet memory _packet;
{
// (b) retrieve UA's validation library
address inboundProofLib = inboundProofLibrary[_srcChainId][uaConfig.inboundProofLibraryVersion];
// (c) assert that the data submitted by UA's oracle have no fewer confirmations than UA's configuration
BlockData storage blockData = hashLookup[uaConfig.oracle][_srcChainId][_lookupHash];
require(blockData.confirmations >= uaConfig.inboundBlockConfirmations, "LayerZero: not enough block confirmations");
// (d) decode
uint remoteAddressSize = chainAddressSizeMap[_srcChainId];
_packet = ILayerZeroValidationLibrary(inboundProofLib).validateProof(blockData.data, _transactionProof, remoteAddressSize);
}
// (e) assert that the packet was emitted by the source ultra light node
require(ulnLookup[_srcChainId] == _packet.ulnAddress, "LayerZero: _packet.ulnAddress is invalid");
// (f) assert that the _packet._dstAddress == the _dstAddress specified by the UAs message
require(_packet.dstAddress == _dstAddress, "LayerZero: invalid dst address");
// publish the payload and _gasLimit to the endpoint for calling lzReceive at _dstAddress
endpoint.receivePayload(_packet.srcChainId, _packet.srcAddress, _packet.dstAddress, _packet.nonce, _gasLimit, _packet.payload);
}
// Called (by the Endpoint) with the information required to send a LayerZero message for a User Application.
// This function:
// (a) pays the protocol (native token or ZRO), oracle (native token) and relayer (native token) for their roles in sending the message.
// (b) generates the message payload and emits events of the message and adapterParams
// (c) notifies the oracle
function send(address _ua, uint64 _nonce, uint16 _chainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable override onlyEndpoint {
ApplicationConfiguration memory uaConfig = getAppConfig(_chainId, _ua);
address ua = _ua;
uint64 nonce = _nonce;
uint16 chainId = _chainId;
require(ulnLookup[chainId] != bytes32(0), "LayerZero: chainId does not exist");
uint totalNativeFee;
{
uint oracleFee;
// (a - 1), pay the oracle
{
oracleFee = ILayerZeroOracle(uaConfig.oracle).getPrice(chainId, uaConfig.outboundProofType);
oracleQuotedFees[uaConfig.oracle] = oracleQuotedFees[uaConfig.oracle].add(oracleFee);
}
// (a - 2), pay the relayer
{
uint payloadSize = _payload.length;
ILayerZeroRelayer relayer = ILayerZeroRelayer(uaConfig.relayer);
if (_adapterParams.length == 0) {
bytes memory defaultAdaptorParam = defaultAdapterParams[chainId][uaConfig.outboundProofType];
totalNativeFee = relayer.getPrice(chainId, uaConfig.outboundProofType, ua, payloadSize, defaultAdaptorParam);
relayer.notifyRelayer(chainId, uaConfig.outboundProofType, defaultAdaptorParam);
} else {
totalNativeFee = relayer.getPrice(chainId, uaConfig.outboundProofType, ua, payloadSize, _adapterParams);
relayer.notifyRelayer(chainId, uaConfig.outboundProofType, _adapterParams);
}
relayerQuotedFees[uaConfig.relayer] = relayerQuotedFees[uaConfig.relayer].add(totalNativeFee); // totalNativeFee == relayerFee here
// emit the param events
emit RelayerParams(chainId, nonce, uaConfig.outboundProofType, _adapterParams);
}
// (a - 3), pay the protocol
{
// if no ZRO token or not specifying a payment address, pay in native token
bool payInNative = _zroPaymentAddress == address(0x0) || address(layerZeroToken) == address(0x0);
uint protocolFee = treasuryContract.getFees(!payInNative, totalNativeFee, oracleFee); // totalNativeFee == relayerFee here
if (protocolFee > 0) {
if (payInNative) {
treasuryNativeFees = treasuryNativeFees.add(protocolFee);
totalNativeFee = totalNativeFee.add(protocolFee);
} else {
// zro payment address must equal the _ua or the tx.origin otherwise the transaction reverts
require(_zroPaymentAddress == ua || _zroPaymentAddress == tx.origin, "LayerZero: must be paid by sender or origin");
// transfer the LayerZero token to this contract from the payee
layerZeroToken.safeTransferFrom(_zroPaymentAddress, address(this), protocolFee);
treasuryZROFees = treasuryZROFees.add(protocolFee);
}
}
}
totalNativeFee = totalNativeFee.add(oracleFee);
}
// (b) emit payload and the adapterParams if any
{
bytes memory encodedPayload = abi.encodePacked(nonce, ua, _destination, _payload);
emit Packet(chainId, encodedPayload);
// (c) notify the oracle
ILayerZeroOracle(uaConfig.oracle).notifyOracle(chainId, uaConfig.outboundProofType, uaConfig.outboundBlockConfirmations);
}
require(totalNativeFee <= msg.value, "LayerZero: not enough native for fees");
// refund if they send too much
uint amount = msg.value.sub(totalNativeFee);
if (amount > 0) {
(bool success, ) = _refundAddress.call{value: amount}("");
require(success, "LayerZero: failed to refund");
}
}
// Can be called by any address to update a block header
// can only upload new block data or the same block data with more confirmations
function updateHash(uint16 _srcChainId, bytes32 _lookupHash, uint _confirmations, bytes32 _data) external override {
// this function may revert with a default message if the oracle address is not an ILayerZeroOracle
BlockData storage bd = hashLookup[msg.sender][_srcChainId][_lookupHash];
// if it has a record, requires a larger confirmation.
require(bd.confirmations < _confirmations, "LayerZero: oracle data can only update if it has more confirmations");
// set the new information into storage
bd.confirmations = _confirmations;
bd.data = _data;
emit HashReceived(_srcChainId, msg.sender, _confirmations, _lookupHash);
}
//----------------------------------------------------------------------------------
// Other Library Interfaces
// default to DEFAULT setting if ZERO value
function getAppConfig(uint16 _chainId, address userApplicationAddress) public view returns (ApplicationConfiguration memory) {
ApplicationConfiguration memory config = appConfig[userApplicationAddress][_chainId];
ApplicationConfiguration storage defaultConfig = defaultAppConfig[_chainId];
if (config.inboundProofLibraryVersion == 0) {
config.inboundProofLibraryVersion = defaultConfig.inboundProofLibraryVersion;
}
if (config.inboundBlockConfirmations == 0) {
config.inboundBlockConfirmations = defaultConfig.inboundBlockConfirmations;
}
if (config.relayer == address(0x0)) {
config.relayer = defaultConfig.relayer;
}
if (config.outboundProofType == 0) {
config.outboundProofType = defaultConfig.outboundProofType;
}
if (config.outboundBlockConfirmations == 0) {
config.outboundBlockConfirmations = defaultConfig.outboundBlockConfirmations;
}
if (config.oracle == address(0x0)) {
config.oracle = defaultConfig.oracle;
}
return config;
}
function setConfig(uint16 chainId, address _ua, uint _configType, bytes calldata _config) external override onlyEndpoint {
ApplicationConfiguration storage uaConfig = appConfig[_ua][chainId];
if (_configType == CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION) {
uint16 inboundProofLibraryVersion = abi.decode(_config, (uint16));
require(inboundProofLibraryVersion <= maxInboundProofLibrary[chainId], "LayerZero: invalid inbound proof library version");
uaConfig.inboundProofLibraryVersion = inboundProofLibraryVersion;
} else if (_configType == CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS) {
uint64 blockConfirmations = abi.decode(_config, (uint64));
uaConfig.inboundBlockConfirmations = blockConfirmations;
} else if (_configType == CONFIG_TYPE_RELAYER) {
address relayer = abi.decode(_config, (address));
uaConfig.relayer = relayer;
} else if (_configType == CONFIG_TYPE_OUTBOUND_PROOF_TYPE) {
uint16 outboundProofType = abi.decode(_config, (uint16));
require(supportedOutboundProof[chainId][outboundProofType] || outboundProofType == 0, "LayerZero: invalid outbound proof type");
uaConfig.outboundProofType = outboundProofType;
} else if (_configType == CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS) {
uint64 blockConfirmations = abi.decode(_config, (uint64));
uaConfig.outboundBlockConfirmations = blockConfirmations;
} else if (_configType == CONFIG_TYPE_ORACLE) {
address oracle = abi.decode(_config, (address));
uaConfig.oracle = oracle;
} else {
revert("LayerZero: Invalid config type");
}
emit AppConfigUpdated(_ua, _configType, _config);
}
function getConfig(uint16 _chainId, address userApplicationAddress, uint _configType) external view override returns (bytes memory) {
ApplicationConfiguration storage uaConfig = appConfig[userApplicationAddress][_chainId];
if (_configType == CONFIG_TYPE_INBOUND_PROOF_LIBRARY_VERSION) {
if (uaConfig.inboundProofLibraryVersion == 0) {
return abi.encode(defaultAppConfig[_chainId].inboundProofLibraryVersion);
}
return abi.encode(uaConfig.inboundProofLibraryVersion);
} else if (_configType == CONFIG_TYPE_INBOUND_BLOCK_CONFIRMATIONS) {
if (uaConfig.inboundBlockConfirmations == 0) {
return abi.encode(defaultAppConfig[_chainId].inboundBlockConfirmations);
}
return abi.encode(uaConfig.inboundBlockConfirmations);
} else if (_configType == CONFIG_TYPE_RELAYER) {
if (uaConfig.relayer == address(0x0)) {
return abi.encode(defaultAppConfig[_chainId].relayer);
}
return abi.encode(uaConfig.relayer);
} else if (_configType == CONFIG_TYPE_OUTBOUND_PROOF_TYPE) {
if (uaConfig.outboundProofType == 0) {
return abi.encode(defaultAppConfig[_chainId].outboundProofType);
}
return abi.encode(uaConfig.outboundProofType);
} else if (_configType == CONFIG_TYPE_OUTBOUND_BLOCK_CONFIRMATIONS) {
if (uaConfig.outboundBlockConfirmations == 0) {
return abi.encode(defaultAppConfig[_chainId].outboundBlockConfirmations);
}
return abi.encode(uaConfig.outboundBlockConfirmations);
} else if (_configType == CONFIG_TYPE_ORACLE) {
if (uaConfig.oracle == address(0x0)) {
return abi.encode(defaultAppConfig[_chainId].oracle);
}
return abi.encode(uaConfig.oracle);
} else {
revert("LayerZero: Invalid config type");
}
}
// returns the native fee the UA pays to cover fees
function estimateFees(uint16 _chainId, address _ua, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParams) external view override returns (uint nativeFee, uint zroFee) {
uint16 chainId = _chainId;
address ua = _ua;
uint payloadSize = _payload.length;
bytes memory adapterParam = _adapterParams;
ApplicationConfiguration memory uaConfig = getAppConfig(chainId, ua);
// Relayer Fee
uint relayerFee;
{
if (adapterParam.length == 0) {
bytes memory defaultAdaptorParam = defaultAdapterParams[chainId][uaConfig.outboundProofType];
relayerFee = ILayerZeroRelayer(uaConfig.relayer).getPrice(chainId, uaConfig.outboundProofType, ua, payloadSize, defaultAdaptorParam);
} else {
relayerFee = ILayerZeroRelayer(uaConfig.relayer).getPrice(chainId, uaConfig.outboundProofType, ua, payloadSize, adapterParam);
}
}
// Oracle Fee
uint oracleFee = ILayerZeroOracle(uaConfig.oracle).getPrice(chainId, uaConfig.outboundProofType);
// LayerZero Fee
{
uint protocolFee = treasuryContract.getFees(_payInZRO, relayerFee, oracleFee);
_payInZRO ? zroFee = protocolFee : nativeFee = protocolFee;
}
// return the sum of fees
nativeFee = nativeFee.add(relayerFee).add(oracleFee);
}
//---------------------------------------------------------------------------
// Claim Fees
// universal withdraw ZRO token function
function withdrawZRO(address _to, uint _amount) external override nonReentrant {
require(msg.sender == address(treasuryContract), "LayerZero: only treasury");
treasuryZROFees = treasuryZROFees.sub(_amount);
layerZeroToken.safeTransfer(_to, _amount);
emit WithdrawZRO(msg.sender, _to, _amount);
}
// universal withdraw native token function.
// the source contract should perform all the authentication control
// safemath overflow if the amount is not enough
function withdrawNative(uint8 _type, address _owner, address payable _to, uint _amount) external override nonReentrant {
if (_type == WITHDRAW_TYPE_TREASURY_PROTOCOL_FEES) {
require(msg.sender == address(treasuryContract), "LayerZero:only treasury");
treasuryNativeFees = treasuryNativeFees.sub(_amount);
} else if (_type == WITHDRAW_TYPE_ORACLE_QUOTED_FEES) {
oracleQuotedFees[msg.sender] = oracleQuotedFees[msg.sender].sub(_amount);
} else if (_type == WITHDRAW_TYPE_RELAYER_QUOTED_FEES) {
relayerQuotedFees[msg.sender] = relayerQuotedFees[msg.sender].sub(_amount);
} else {
revert("LayerZero: unsupported withdraw type");
}
(bool success, ) = _to.call{value: _amount}("");
require(success, "LayerZero: withdraw failed");
emit WithdrawNative(_type, _owner, msg.sender, _to, _amount);
}
//---------------------------------------------------------------------------
// Owner calls, configuration only.
function setLayerZeroToken(address _layerZeroToken) external onlyOwner {
require(_layerZeroToken != address(0x0), "LayerZero: _layerZeroToken cannot be zero address");
layerZeroToken = IERC20(_layerZeroToken);
emit SetLayerZeroToken(_layerZeroToken);
}
function setTreasury(address _treasury) external onlyOwner {
require(_treasury != address(0x0), "LayerZero: treasury cannot be zero address");
treasuryContract = ILayerZeroTreasury(_treasury);
emit SetTreasury(_treasury);
}
function addInboundProofLibraryForChain(uint16 _chainId, address _library) external onlyOwner {
require(_library != address(0x0), "LayerZero: library cannot be zero address");
require(maxInboundProofLibrary[_chainId] < 65535, "LayerZero: can not add new library");
maxInboundProofLibrary[_chainId]++;
inboundProofLibrary[_chainId][maxInboundProofLibrary[_chainId]] = _library;
emit AddInboundProofLibraryForChain(_chainId, _library);
}
function enableSupportedOutboundProof(uint16 _chainId, uint16 _proofType) external onlyOwner {
supportedOutboundProof[_chainId][_proofType] = true;
emit EnableSupportedOutboundProof(_chainId, _proofType);
}
function setDefaultConfigForChainId(uint16 _chainId, uint16 _inboundProofLibraryVersion, uint64 _inboundBlockConfirmations, address _relayer, uint16 _outboundProofType, uint16 _outboundBlockConfirmations, address _oracle) external onlyOwner {
require(_inboundProofLibraryVersion <= maxInboundProofLibrary[_chainId] && _inboundProofLibraryVersion > 0, "LayerZero: invalid inbound proof library version");
require(_inboundBlockConfirmations > 0, "LayerZero: invalid inbound block confirmation");
require(_relayer != address(0x0), "LayerZero: invalid relayer address");
require(supportedOutboundProof[_chainId][_outboundProofType], "LayerZero: invalid outbound proof type");
require(_outboundBlockConfirmations > 0, "LayerZero: invalid outbound block confirmation");
require(_oracle != address(0x0), "LayerZero: invalid oracle address");
defaultAppConfig[_chainId] = ApplicationConfiguration(_inboundProofLibraryVersion, _inboundBlockConfirmations, _relayer, _outboundProofType, _outboundBlockConfirmations, _oracle);
emit SetDefaultConfigForChainId(_chainId, _inboundProofLibraryVersion, _inboundBlockConfirmations, _relayer, _outboundProofType, _outboundBlockConfirmations, _oracle);
}
function setDefaultAdapterParamsForChainId(uint16 _chainId, uint16 _proofType, bytes calldata _adapterParams) external onlyOwner {
defaultAdapterParams[_chainId][_proofType] = _adapterParams;
emit SetDefaultAdapterParamsForChainId(_chainId, _proofType, _adapterParams);
}
function setRemoteUln(uint16 _remoteChainId, bytes32 _remoteUln) external onlyOwner {
require(ulnLookup[_remoteChainId] == bytes32(0), "LayerZero: remote uln already set");
ulnLookup[_remoteChainId] = _remoteUln;
emit SetRemoteUln(_remoteChainId, _remoteUln);
}
function setChainAddressSize(uint16 _chainId, uint _size) external onlyOwner {
require(chainAddressSizeMap[_chainId] == 0, "LayerZero: remote chain address size already set");
chainAddressSizeMap[_chainId] = _size;
emit SetChainAddressSize(_chainId, _size);
}
//----------------------------------------------------------------------------------
// view functions
function getBlockHeaderData(address _oracle, uint16 _remoteChainId, bytes32 _lookupHash) external view returns (BlockData memory blockData) {
return hashLookup[_oracle][_remoteChainId][_lookupHash];
}
function oracleQuotedAmount(address _oracle) external view override returns (uint) {
return oracleQuotedFees[_oracle];
}
function relayerQuotedAmount(address _relayer) external view override returns (uint) {
return relayerQuotedFees[_relayer];
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
pragma abicoder v2;
import "./utility/LayerZeroPacket.sol";
interface ILayerZeroValidationLibrary {
function validateProof(bytes32 blockData, bytes calldata _data, uint _remoteAddressSize) external returns (LayerZeroPacket.Packet memory packet);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroMessagingLibrary {
// send(), messages will be inflight.
function send(address _userApplication, uint64 _lastNonce, uint16 _chainId, bytes calldata _destination, bytes calldata _payload, address payable refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// estimate native fee at the send side
function estimateFees(uint16 _chainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
//---------------------------------------------------------------------------
// setConfig / getConfig are User Application (UA) functions to specify Oracle, Relayer, blockConfirmations, libraryVersion
function setConfig(uint16 _chainId, address _userApplication, uint _configType, bytes calldata _config) external;
function getConfig(uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination
// @param _srcChainId - the source endpoint identifier
// @param _srcAddress - the source sending contract address from the source chain
// @param _nonce - the ordered message nonce
// @param _payload - the signed payload is the UA bytes has encoded to be sent
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
interface ILayerZeroRelayer {
// @notice query the relayer price for relaying the payload and its proof to the destination chain
// @param _dstChainId - the destination endpoint identifier
// @param _outboundProofType - the proof type identifier to specify proof to be relayed
// @param _userApplication - the source sending contract address. relayers may apply price discrimination to user apps
// @param _payloadSize - the length of the payload. it is an indicator of gas usage for relaying cross-chain messages
// @param _adapterParams - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
function getPrice(uint16 _dstChainId, uint16 _outboundProofType, address _userApplication, uint _payloadSize, bytes calldata _adapterParams) external view returns (uint price);
// @notice Ultra-Light Node notifies the Oracle of a new block information relaying request
// @param _dstChainId - the destination endpoint identifier
// @param _outboundProofType - the proof type identifier to specify the data to be relayed
// @param _adapterParams - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
function notifyRelayer(uint16 _dstChainId, uint16 _outboundProofType, bytes calldata _adapterParams) external;
// @notice query if the address is an approved actor for privileges like data submission and fee withdrawal etc.
// @param _address - the address to be checked
function isApproved(address _address) external view returns (bool approved);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroTreasury {
function getFees(bool payInZro, uint relayerFee, uint oracleFee) external view returns (uint);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
interface ILayerZeroOracle {
// @notice query the oracle price for relaying block information to the destination chain
// @param _dstChainId the destination endpoint identifier
// @param _outboundProofType the proof type identifier to specify the data to be relayed
function getPrice(uint16 _dstChainId, uint16 _outboundProofType) external view returns (uint price);
// @notice Ultra-Light Node notifies the Oracle of a new block information relaying request
// @param _dstChainId the destination endpoint identifier
// @param _outboundProofType the proof type identifier to specify the data to be relayed
// @param _outboundBlockConfirmations the number of source chain block confirmation needed
function notifyOracle(uint16 _dstChainId, uint16 _outboundProofType, uint64 _outboundBlockConfirmations) external;
// @notice query if the address is an approved actor for privileges like data submission and fee withdrawal etc.
// @param _address the address to be checked
function isApproved(address _address) external view returns (bool approved);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
interface ILayerZeroUltraLightNodeV1 {
// a Relayer can execute the validateTransactionProof()
function validateTransactionProof(uint16 _srcChainId, address _dstAddress, uint _gasLimit, bytes32 _lookupHash, bytes calldata _transactionProof) external;
// an Oracle delivers the block data using updateHash()
function updateHash(uint16 _remoteChainId, bytes32 _lookupHash, uint _confirmations, bytes32 _data) external;
// can only withdraw the receivable of the msg.sender
function withdrawNative(uint8 _type, address _owner, address payable _to, uint _amount) external;
function withdrawZRO(address _to, uint _amount) external;
// view functions
function oracleQuotedAmount(address _oracle) external view returns (uint);
function relayerQuotedAmount(address _relayer) external view returns (uint);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.
// @param _dstChainId - the destination chain identifier
// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
// @param _payload - a custom bytes payload to send to the destination contract
// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
// @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// @notice used by the messaging library to publish verified payload
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source contract (as bytes) at the source chain
// @param _dstAddress - the address on destination chain
// @param _nonce - the unbound message ordering nonce
// @param _gasLimit - the gas limit for external contract execution
// @param _payload - verified payload to send to the destination contract
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
// @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM
// @param _srcAddress - the source chain contract address
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
// @param _dstChainId - the destination chain identifier
// @param _userApplication - the user app address on this EVM chain
// @param _payload - the custom message to send over LayerZero
// @param _payInZRO - if false, user app pays the protocol fee in native token
// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
// @notice get this Endpoint's immutable source identifier
function getChainId() external view returns (uint16);
// @notice the interface to retry failed message on this Endpoint destination
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
// @param _payload - the payload to be retried
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
// @notice query if any STORED payload (message blocking) at the endpoint.
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.
// @param _userApplication - the user app address on this EVM chain
function getSendLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.
// @param _userApplication - the user app address on this EVM chain
function getReceiveLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the non-reentrancy guard for send() is on
// @return true if the guard is on. false otherwise
function isSendingPayload() external view returns (bool);
// @notice query if the non-reentrancy guard for receive() is on
// @return true if the guard is on. false otherwise
function isReceivingPayload() external view returns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _userApplication - the contract address of the user application
// @param _configType - type of configuration. every messaging library has its own convention.
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
// @notice get the send() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getSendVersion(address _userApplication) external view returns (uint16);
// @notice get the lzReceive() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getReceiveVersion(address _userApplication) external view returns (uint16);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./Buffer.sol";
library LayerZeroPacket {
using Buffer for Buffer.buffer;
using SafeMath for uint;
//---------------------------------------------------------------------------
// packet
struct Packet {
uint16 srcChainId;
uint16 dstChainId;
uint64 nonce;
address dstAddress;
bytes srcAddress;
bytes32 ulnAddress;
bytes payload;
}
function getPacket(bytes memory data, uint16 srcChain, uint sizeOfSrcAddress, bytes32 ulnAddress) internal pure returns (Packet memory) {
uint16 dstChainId;
address dstAddress;
uint size;
uint64 nonce;
// The log consists of the destination chain id and then a bytes payload
// 0--------------------------------------------31
// 0 | destination chain id
// 32 | defines bytes array
// 64 |
// 96 | bytes array size
// 128 | payload
assembly {
dstChainId := mload(add(data, 32))
size := mload(add(data, 96)) /// size of the byte array
nonce := mload(add(data, 104)) // offset to convert to uint64 128 is index -24
dstAddress := mload(add(data, sub(add(128, sizeOfSrcAddress), 4))) // offset to convert to address 12 -8
}
Buffer.buffer memory srcAddressBuffer;
srcAddressBuffer.init(sizeOfSrcAddress);
srcAddressBuffer.writeRawBytes(0, data, 136, sizeOfSrcAddress); // 128 + 8
uint payloadSize = size.sub(20).sub(sizeOfSrcAddress);
Buffer.buffer memory payloadBuffer;
payloadBuffer.init(payloadSize);
payloadBuffer.writeRawBytes(0, data, sizeOfSrcAddress.add(156), payloadSize); // 148 + 8
return Packet(srcChain, dstChainId, nonce, address(dstAddress), srcAddressBuffer.buf, ulnAddress, payloadBuffer.buf);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.7.0;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for writing to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.a co
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns (buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
mstore(0x40, add(32, add(ptr, capacity)))
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/
function fromBytes(bytes memory b) internal pure returns (buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
function max(uint a, uint b) private pure returns (uint) {
if (a > b) {
return a;
}
return b;
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/
function truncate(buffer memory buf) internal pure returns (buffer memory) {
assembly {
let bufptr := mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Writes a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The start offset to write to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns (buffer memory) {
require(len <= data.length);
if (off + len > buf.capacity) {
resize(buf, max(buf.capacity, len + off) * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(add(len, off), buflen) {
mstore(bufptr, add(len, off))
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256**(32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
return buf;
}
/**
* @dev Writes a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The start offset to write to.
* @param rawData The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function writeRawBytes(buffer memory buf, uint off, bytes memory rawData, uint offData, uint len) internal pure returns (buffer memory) {
if (off + len > buf.capacity) {
resize(buf, max(buf.capacity, len + off) * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(add(len, off), buflen) {
mstore(bufptr, add(len, off))
}
src := add(rawData, offData)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256**(32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, len);
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, data.length);
}
/**
* @dev Writes a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write the byte at.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns (buffer memory) {
if (off >= buf.capacity) {
resize(buf, buf.capacity * 2);
}
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Address = buffer address + sizeof(buffer length) + off
let dest := add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended it
if eq(off, buflen) {
mstore(bufptr, add(buflen, 1))
}
}
return buf;
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) {
return writeUint8(buf, buf.buf.length, data);
}
/**
* @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/
function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns (buffer memory) {
if (len + off > buf.capacity) {
resize(buf, (len + off) * 2);
}
uint mask = 256**len - 1;
// Right-align data
data = data >> (8 * (32 - len));
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + off + len
let dest := add(add(bufptr, off), len)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(add(off, len), mload(bufptr)) {
mstore(bufptr, add(off, len))
}
}
return buf;
}
/**
* @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
return write(buf, off, bytes32(data), 20);
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/
function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, bytes32(data), 20);
}
function appendBytes8(buffer memory buf, bytes8 data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, bytes32(data), 8);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, 32);
}
/**
* @dev Writes an integer to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer, for chaining.
*/
function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns (buffer memory) {
if (len + off > buf.capacity) {
resize(buf, (len + off) * 2);
}
uint mask = 256**len - 1;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + off + sizeof(buffer length) + len
let dest := add(add(bufptr, off), len)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(add(off, len), mload(bufptr)) {
mstore(bufptr, add(off, len))
}
}
return buf;
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer.
*/
function appendInt(buffer memory buf, uint data, uint len) internal pure returns (buffer memory) {
return writeInt(buf, buf.buf.length, data, len);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
// @notice set the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _configType - type of configuration. every messaging library has its own convention.
// @param _config - configuration in the bytes. can encode arbitrary content.
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
// @notice set the send() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
// @param _srcChainId - the chainId of the source chain
// @param _srcAddress - the contract address of the source contract at the source chain
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}
File 2 of 2: Endpoint
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "./interfaces/ILayerZeroReceiver.sol";
import "./interfaces/ILayerZeroEndpoint.sol";
import "./interfaces/ILayerZeroMessagingLibrary.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Endpoint is Ownable, ILayerZeroEndpoint {
uint16 public immutable chainId;
// installed libraries and reserved versions
uint16 public constant BLOCK_VERSION = 65535;
uint16 public constant DEFAULT_VERSION = 0;
uint16 public latestVersion;
mapping(uint16 => ILayerZeroMessagingLibrary) public libraryLookup; // version -> ILayerZeroEndpointLibrary
// default send/receive libraries
uint16 public defaultSendVersion;
uint16 public defaultReceiveVersion;
ILayerZeroMessagingLibrary public defaultSendLibrary;
address public defaultReceiveLibraryAddress;
struct LibraryConfig {
uint16 sendVersion;
uint16 receiveVersion;
address receiveLibraryAddress;
ILayerZeroMessagingLibrary sendLibrary;
}
struct StoredPayload {
uint64 payloadLength;
address dstAddress;
bytes32 payloadHash;
}
// user app config = [uaAddress]
mapping(address => LibraryConfig) public uaConfigLookup;
// inboundNonce = [srcChainId][srcAddress].
mapping(uint16 => mapping(bytes => uint64)) public inboundNonce;
// outboundNonce = [dstChainId][srcAddress].
mapping(uint16 => mapping(address => uint64)) public outboundNonce;
// storedPayload = [srcChainId][srcAddress]
mapping(uint16 => mapping(bytes => StoredPayload)) public storedPayload;
// library versioning events
event NewLibraryVersionAdded(uint16 version);
event DefaultSendVersionSet(uint16 version);
event DefaultReceiveVersionSet(uint16 version);
event UaSendVersionSet(address ua, uint16 version);
event UaReceiveVersionSet(address ua, uint16 version);
event UaForceResumeReceive(uint16 chainId, bytes srcAddress);
// payload events
event PayloadCleared(uint16 srcChainId, bytes srcAddress, uint64 nonce, address dstAddress);
event PayloadStored(uint16 srcChainId, bytes srcAddress, address dstAddress, uint64 nonce, bytes payload, bytes reason);
constructor(uint16 _chainId) {
chainId = _chainId;
}
//---------------------------------------------------------------------------
// send and receive nonreentrant lock
uint8 internal constant _NOT_ENTERED = 1;
uint8 internal constant _ENTERED = 2;
uint8 internal _send_entered_state = 1;
uint8 internal _receive_entered_state = 1;
modifier sendNonReentrant() {
require(_send_entered_state == _NOT_ENTERED, "LayerZero: no send reentrancy");
_send_entered_state = _ENTERED;
_;
_send_entered_state = _NOT_ENTERED;
}
modifier receiveNonReentrant() {
require(_receive_entered_state == _NOT_ENTERED, "LayerZero: no receive reentrancy");
_receive_entered_state = _ENTERED;
_;
_receive_entered_state = _NOT_ENTERED;
}
// BLOCK_VERSION is also a valid version
modifier validVersion(uint16 _version) {
require(_version <= latestVersion || _version == BLOCK_VERSION, "LayerZero: invalid messaging library version");
_;
}
//---------------------------------------------------------------------------
// User Application Calls - Endpoint Interface
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable override sendNonReentrant {
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uint64 nonce = ++outboundNonce[_dstChainId][msg.sender];
_getSendLibrary(uaConfig).send{value: msg.value}(msg.sender, nonce, _dstChainId, _destination, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
}
//---------------------------------------------------------------------------
// authenticated Library (msg.sender) Calls to pass through Endpoint to UA (dstAddress)
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external override receiveNonReentrant {
// assert and increment the nonce. no message shuffling
require(_nonce == ++inboundNonce[_srcChainId][_srcAddress], "LayerZero: wrong nonce");
LibraryConfig storage uaConfig = uaConfigLookup[_dstAddress];
// authentication to prevent cross-version message validation
// protects against a malicious library from passing arbitrary data
if (uaConfig.receiveVersion == DEFAULT_VERSION) {
require(defaultReceiveLibraryAddress == msg.sender, "LayerZero: invalid default library");
} else {
require(uaConfig.receiveLibraryAddress == msg.sender, "LayerZero: invalid library");
}
// block if any message blocking
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
require(sp.payloadHash == bytes32(0), "LayerZero: in message blocking");
try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _srcAddress, _nonce, _payload) {
// success, do nothing, end of the message delivery
} catch (bytes memory reason) {
// revert nonce if any uncaught errors/exceptions if the ua chooses the blocking mode
storedPayload[_srcChainId][_srcAddress] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));
emit PayloadStored(_srcChainId, _srcAddress, _dstAddress, _nonce, _payload, reason);
}
}
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external override receiveNonReentrant {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
require(sp.payloadHash != bytes32(0), "LayerZero: no stored payload");
require(_payload.length == sp.payloadLength && keccak256(_payload) == sp.payloadHash, "LayerZero: invalid payload");
address dstAddress = sp.dstAddress;
// empty the storedPayload
sp.payloadLength = 0;
sp.dstAddress = address(0);
sp.payloadHash = bytes32(0);
uint64 nonce = inboundNonce[_srcChainId][_srcAddress];
ILayerZeroReceiver(dstAddress).lzReceive(_srcChainId, _srcAddress, nonce, _payload);
emit PayloadCleared(_srcChainId, _srcAddress, nonce, dstAddress);
}
//---------------------------------------------------------------------------
// Owner Calls, only new library version upgrade (3 steps)
// note libraryLookup[0] = 0x0, no library implementation
// LIBRARY UPGRADE step 1: set _newLayerZeroLibraryAddress be the new version
function newVersion(address _newLayerZeroLibraryAddress) external onlyOwner {
require(_newLayerZeroLibraryAddress != address(0x0), "LayerZero: new version cannot be zero address");
require(latestVersion < 65535, "LayerZero: can not add new messaging library");
latestVersion++;
libraryLookup[latestVersion] = ILayerZeroMessagingLibrary(_newLayerZeroLibraryAddress);
emit NewLibraryVersionAdded(latestVersion);
}
// LIBRARY UPGRADE step 2: stop sending messages from the old version
function setDefaultSendVersion(uint16 _newDefaultSendVersion) external onlyOwner validVersion(_newDefaultSendVersion) {
require(_newDefaultSendVersion != DEFAULT_VERSION, "LayerZero: default send version must > 0");
defaultSendVersion = _newDefaultSendVersion;
defaultSendLibrary = libraryLookup[defaultSendVersion];
emit DefaultSendVersionSet(_newDefaultSendVersion);
}
// LIBRARY UPGRADE step 3: stop receiving messages from the old version
function setDefaultReceiveVersion(uint16 _newDefaultReceiveVersion) external onlyOwner validVersion(_newDefaultReceiveVersion) {
require(_newDefaultReceiveVersion != DEFAULT_VERSION, "LayerZero: default receive version must > 0");
defaultReceiveVersion = _newDefaultReceiveVersion;
defaultReceiveLibraryAddress = address(libraryLookup[defaultReceiveVersion]);
emit DefaultReceiveVersionSet(_newDefaultReceiveVersion);
}
//---------------------------------------------------------------------------
// User Application Calls - UA set/get Interface
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override validVersion(_version) {
if (_version == DEFAULT_VERSION) {
require(defaultSendVersion == defaultReceiveVersion, "LayerZero: can not set Config during DEFAULT migration");
_version = defaultSendVersion;
}
require(_version != BLOCK_VERSION, "LayerZero: can not set config for BLOCK_VERSION");
libraryLookup[_version].setConfig(_chainId, msg.sender, _configType, _config);
}
// Migration step 1: set the send version
// Define what library the UA points too
function setSendVersion(uint16 _newVersion) external override validVersion(_newVersion) {
// write into config
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uaConfig.sendVersion = _newVersion;
// the libraryLookup[BLOCK_VERSION || DEFAULT_VERSION] = 0x0
uaConfig.sendLibrary = libraryLookup[_newVersion];
emit UaSendVersionSet(msg.sender, _newVersion);
}
// Migration step 2: set the receive version
// after all messages sent from the old version are received
// the UA can now safely switch to the new receive version
// it is the UA's responsibility make sure all messages from the old version are processed
function setReceiveVersion(uint16 _newVersion) external override validVersion(_newVersion) {
// write into config
LibraryConfig storage uaConfig = uaConfigLookup[msg.sender];
uaConfig.receiveVersion = _newVersion;
// the libraryLookup[BLOCK_VERSION || DEFAULT_VERSION] = 0x0
uaConfig.receiveLibraryAddress = address(libraryLookup[_newVersion]);
emit UaReceiveVersionSet(msg.sender, _newVersion);
}
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
// revert if no messages are cached. safeguard malicious UA behaviour
require(sp.payloadHash != bytes32(0), "LayerZero: no stored payload");
require(sp.dstAddress == msg.sender, "LayerZero: invalid caller");
// empty the storedPayload
sp.payloadLength = 0;
sp.dstAddress = address(0);
sp.payloadHash = bytes32(0);
// emit the event with the new nonce
emit UaForceResumeReceive(_srcChainId, _srcAddress);
}
//---------------------------------------------------------------------------
// view helper function
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParams) external view override returns (uint nativeFee, uint zroFee) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
ILayerZeroMessagingLibrary lib = uaConfig.sendVersion == DEFAULT_VERSION ? defaultSendLibrary : uaConfig.sendLibrary;
return lib.estimateFees(_dstChainId, _userApplication, _payload, _payInZRO, _adapterParams);
}
function _getSendLibrary(LibraryConfig storage uaConfig) internal view returns (ILayerZeroMessagingLibrary) {
if (uaConfig.sendVersion == DEFAULT_VERSION) {
// check if the in send-blocking upgrade
require(defaultSendVersion != BLOCK_VERSION, "LayerZero: default in BLOCK_VERSION");
return defaultSendLibrary;
} else {
// check if the in send-blocking upgrade
require(uaConfig.sendVersion != BLOCK_VERSION, "LayerZero: in BLOCK_VERSION");
return uaConfig.sendLibrary;
}
}
function getSendLibraryAddress(address _userApplication) external view override returns (address sendLibraryAddress) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
uint16 sendVersion = uaConfig.sendVersion;
require(sendVersion != BLOCK_VERSION, "LayerZero: send version is BLOCK_VERSION");
if (sendVersion == DEFAULT_VERSION) {
require(defaultSendVersion != BLOCK_VERSION, "LayerZero: send version (default) is BLOCK_VERSION");
sendLibraryAddress = address(defaultSendLibrary);
} else {
sendLibraryAddress = address(uaConfig.sendLibrary);
}
}
function getReceiveLibraryAddress(address _userApplication) external view override returns (address receiveLibraryAddress) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
uint16 receiveVersion = uaConfig.receiveVersion;
require(receiveVersion != BLOCK_VERSION, "LayerZero: receive version is BLOCK_VERSION");
if (receiveVersion == DEFAULT_VERSION) {
require(defaultReceiveVersion != BLOCK_VERSION, "LayerZero: receive version (default) is BLOCK_VERSION");
receiveLibraryAddress = defaultReceiveLibraryAddress;
} else {
receiveLibraryAddress = uaConfig.receiveLibraryAddress;
}
}
function isSendingPayload() external view override returns (bool) {
return _send_entered_state == _ENTERED;
}
function isReceivingPayload() external view override returns (bool) {
return _receive_entered_state == _ENTERED;
}
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view override returns (uint64) {
return inboundNonce[_srcChainId][_srcAddress];
}
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view override returns (uint64) {
return outboundNonce[_dstChainId][_srcAddress];
}
function getChainId() external view override returns (uint16) {
return chainId;
}
function getSendVersion(address _userApplication) external view override returns (uint16) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
return uaConfig.sendVersion == DEFAULT_VERSION ? defaultSendVersion : uaConfig.sendVersion;
}
function getReceiveVersion(address _userApplication) external view override returns (uint16) {
LibraryConfig storage uaConfig = uaConfigLookup[_userApplication];
return uaConfig.receiveVersion == DEFAULT_VERSION ? defaultReceiveVersion : uaConfig.receiveVersion;
}
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view override validVersion(_version) returns (bytes memory) {
if (_version == DEFAULT_VERSION) {
require(defaultSendVersion == defaultReceiveVersion, "LayerZero: no DEFAULT config while migration");
_version = defaultSendVersion;
}
require(_version != BLOCK_VERSION, "LayerZero: can not get config for BLOCK_VERSION");
return libraryLookup[_version].getConfig(_chainId, _userApplication, _configType);
}
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view override returns (bool) {
StoredPayload storage sp = storedPayload[_srcChainId][_srcAddress];
return sp.payloadHash != bytes32(0);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination
// @param _srcChainId - the source endpoint identifier
// @param _srcAddress - the source sending contract address from the source chain
// @param _nonce - the ordered message nonce
// @param _payload - the signed payload is the UA bytes has encoded to be sent
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.
// @param _dstChainId - the destination chain identifier
// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
// @param _payload - a custom bytes payload to send to the destination contract
// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
// @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// @notice used by the messaging library to publish verified payload
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source contract (as bytes) at the source chain
// @param _dstAddress - the address on destination chain
// @param _nonce - the unbound message ordering nonce
// @param _gasLimit - the gas limit for external contract execution
// @param _payload - verified payload to send to the destination contract
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
// @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM
// @param _srcAddress - the source chain contract address
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
// @param _dstChainId - the destination chain identifier
// @param _userApplication - the user app address on this EVM chain
// @param _payload - the custom message to send over LayerZero
// @param _payInZRO - if false, user app pays the protocol fee in native token
// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
// @notice get this Endpoint's immutable source identifier
function getChainId() external view returns (uint16);
// @notice the interface to retry failed message on this Endpoint destination
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
// @param _payload - the payload to be retried
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
// @notice query if any STORED payload (message blocking) at the endpoint.
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.
// @param _userApplication - the user app address on this EVM chain
function getSendLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.
// @param _userApplication - the user app address on this EVM chain
function getReceiveLibraryAddress(address _userApplication) external view returns (address);
// @notice query if the non-reentrancy guard for send() is on
// @return true if the guard is on. false otherwise
function isSendingPayload() external view returns (bool);
// @notice query if the non-reentrancy guard for receive() is on
// @return true if the guard is on. false otherwise
function isReceivingPayload() external view returns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _userApplication - the contract address of the user application
// @param _configType - type of configuration. every messaging library has its own convention.
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
// @notice get the send() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getSendVersion(address _userApplication) external view returns (uint16);
// @notice get the lzReceive() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getReceiveVersion(address _userApplication) external view returns (uint16);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroMessagingLibrary {
// send(), messages will be inflight.
function send(address _userApplication, uint64 _lastNonce, uint16 _chainId, bytes calldata _destination, bytes calldata _payload, address payable refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
// estimate native fee at the send side
function estimateFees(uint16 _chainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
//---------------------------------------------------------------------------
// setConfig / getConfig are User Application (UA) functions to specify Oracle, Relayer, blockConfirmations, libraryVersion
function setConfig(uint16 _chainId, address _userApplication, uint _configType, bytes calldata _config) external;
function getConfig(uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
// @notice set the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _configType - type of configuration. every messaging library has its own convention.
// @param _config - configuration in the bytes. can encode arbitrary content.
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
// @notice set the send() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
// @param _srcChainId - the chainId of the source chain
// @param _srcAddress - the contract address of the source contract at the source chain
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}