// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Emitted when the account is not a contract
* @param account The account address
*/errorNonContractAddressError(address account);
/**
* @notice Function to check if the account is a contract
* @return The account contract status flag
*/functionisContract(address _account) viewreturns (bool) {
return _account.code.length>0;
}
/**
* @notice Function to require an account to be a contract
*/functionrequireContract(address _account) view{
if (!isContract(_account)) {
revert NonContractAddressError(_account);
}
}
/**
* @notice Function to require an account to be a contract or a zero address
*/functionrequireContractOrZeroAddress(address _account) view{
if (_account !=address(0)) {
requireContract(_account);
}
}
Contract Source Code
File 2 of 13: Constants.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @dev The default token decimals value
*/uint256constant DECIMALS_DEFAULT =18;
/**
* @dev The maximum uint256 value for swap amount limit settings
*/uint256constant INFINITY =type(uint256).max;
/**
* @dev The default limit of account list size
*/uint256constant LIST_SIZE_LIMIT_DEFAULT =100;
/**
* @dev The limit of swap router list size
*/uint256constant LIST_SIZE_LIMIT_ROUTERS =200;
/**
* @dev The factor for percentage settings. Example: 100 is 0.1%
*/uint256constant MILLIPERCENT_FACTOR =100_000;
/**
* @dev The de facto standard address to denote the native token
*/addressconstant NATIVE_TOKEN_ADDRESS =0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
Contract Source Code
File 3 of 13: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^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 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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 4 of 13: ILayerZeroEndpoint.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ILayerZeroEndpoint
* @notice LayerZero endpoint interface
*/interfaceILayerZeroEndpoint{
/**
* @notice Send a cross-chain message
* @param _dstChainId The destination chain identifier
* @param _destination Remote address concatenated with local address packed into 40 bytes
* @param _payload The message content
* @param _refundAddress Refund the additional amount to this address
* @param _zroPaymentAddress The address of the ZRO token holder who would pay for the transaction
* @param _adapterParam Parameters for the adapter service
*/functionsend(uint16 _dstChainId,
bytescalldata _destination,
bytescalldata _payload,
addresspayable _refundAddress,
address _zroPaymentAddress,
bytescalldata _adapterParam
) externalpayable;
/**
* @notice Cross-chain message fee estimation
* @param _dstChainId The destination chain identifier
* @param _userApplication The application address on the source chain
* @param _payload The message content
* @param _payInZRO If false, the user application pays the protocol fee in the native token
* @param _adapterParam Parameters for the adapter service
* @return nativeFee The native token fee for the message
* @return zroFee The ZRO token fee for the message
*/functionestimateFees(uint16 _dstChainId,
address _userApplication,
bytescalldata _payload,
bool _payInZRO,
bytescalldata _adapterParam
) externalviewreturns (uint256 nativeFee, uint256 zroFee);
}
Contract Source Code
File 5 of 13: ILayerZeroRelayer.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ILayerZeroRelayer
* @notice LayerZero relayer interface
*/interfaceILayerZeroRelayer{
/**
* @notice Destination config lookup
* @param _chainId The chain identifier
* @param _outboundProofType The type of the outbound proof
* @return dstNativeAmtCap The native token amount cap on the destination chain
* @return baseGas The base gas value
* @return gasPerByte The gas value per byte
*/functiondstConfigLookup(uint16 _chainId,
uint16 _outboundProofType
) externalviewreturns (uint128 dstNativeAmtCap, uint64 baseGas, uint64 gasPerByte);
}
Contract Source Code
File 6 of 13: ILayerZeroResumeReceive.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ILayerZeroResumeReceive
* @notice LayerZero queue unblocking interface
*/interfaceILayerZeroResumeReceive{
/**
* @notice Unblocks the LayerZero message queue
* @param _srcChainId The source chain identifier
* @param _srcAddress Remote address concatenated with local address packed into 40 bytes
*/functionforceResumeReceive(uint16 _srcChainId, bytescalldata _srcAddress) external;
}
Contract Source Code
File 7 of 13: ITokenBalance.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title ITokenBalance
* @notice Token balance interface
*/interfaceITokenBalance{
/**
* @notice Getter of the token balance by the account
* @param _account The account address
* @return Token balance
*/functionbalanceOf(address _account) externalviewreturns (uint256);
}
Contract Source Code
File 8 of 13: InterportLZGasTransfer.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { ILayerZeroEndpoint } from'../crosschain/layerzero/interfaces/ILayerZeroEndpoint.sol';
import { ILayerZeroRelayer } from'../crosschain/layerzero/interfaces/ILayerZeroRelayer.sol';
import { ILayerZeroResumeReceive } from'../crosschain/layerzero/interfaces/ILayerZeroResumeReceive.sol';
import { OwnerManageable } from'../access/OwnerManageable.sol';
import { SystemVersionId } from'../SystemVersionId.sol';
import'../helpers/AddressHelper.sol'asAddressHelper;
/**
* @title InterportLZGasTransfer
* @notice Gas transfer contract
*/contractInterportLZGasTransferisSystemVersionId, OwnerManageable{
/**
* @notice Gas transfer parameter data structure
* @param lzChainId LayerZero-specific chain identifier
* @param recipient The address of the gas transfer recipient
* @param amount Gas transfer amount
* @param settings Gas transfer settings
*/structGasTransferParameters {
uint16 lzChainId;
address recipient;
uint256 amount;
bytes settings;
}
/**
* @dev The address of the cross-chain endpoint
*/addresspublic lzEndpoint;
/**
* @dev The address of the cross-chain relayer
*/addresspublic lzRelayer;
uint16privateconstant LZ_ADAPTER_PARAMETERS_VERSION =2;
bytesprivateconstant LZ_PAYLOAD_NONE ='';
uint256private minDstGas;
uint256private minReserve;
/**
* @notice Emitted when the cross-chain endpoint contract reference is set
* @param endpoint The cross-chain endpoint contract address
*/eventSetEndpoint(addressindexed endpoint);
/**
* @notice Emitted when the cross-chain relayer contract reference is set
* @param relayer The cross-chain relayer contract address
*/eventSetRelayer(addressindexed relayer);
/**
* @notice Emitted when the parameter validation results in an error
*/errorValidationError();
/**
* @notice Initializes the InterportLZGasTransfer contract
* @param _lzEndpoint The cross-chain endpoint contract address
* @param _lzRelayer The cross-chain relayer contract address
* @param _validation The initial validation data
* @param _owner The address of the initial owner of the contract
*/constructor(address _lzEndpoint, address _lzRelayer, bytesmemory _validation, address _owner) {
_setEndpoint(_lzEndpoint);
_setRelayer(_lzRelayer);
_setValidation(_validation);
_initOwner(_owner);
}
/**
* @notice The standard "receive" function
*/receive() externalpayable{}
/**
* @notice Performs a gas transfer action
* @param _parameters Gas transfer parameters
*/functiongasTransfer(
GasTransferParameters calldata _parameters
) externalpayablewhenNotPaused{
(uint256 lzValue, address dstApp, bytesmemory lzAdapterParameters) = _getEndpointData(
_parameters,
true
);
ILayerZeroEndpoint(lzEndpoint).send{ value: lzValue }(
_parameters.lzChainId,
abi.encodePacked(dstApp, address(this)),
LZ_PAYLOAD_NONE,
payable(this),
address(0),
lzAdapterParameters
);
}
/**
* @notice Receives cross-chain messages
* @dev The function is called by the cross-chain endpoint
*/functionlzReceive(uint16, bytescalldata, uint64, bytescalldata) external{}
/**
* @notice Unblocks the cross-chain message queue
* @param _lzSourceChainId The source chain identifier (LayerZero-specific)
* @param _sourceApp The source chain app address
*/functionresumeReceive(uint16 _lzSourceChainId, address _sourceApp) external{
ILayerZeroResumeReceive(lzEndpoint).forceResumeReceive(
_lzSourceChainId,
abi.encodePacked(_sourceApp, address(this))
);
}
/**
* @notice Sets the cross-chain endpoint contract reference
* @param _lzEndpoint The cross-chain endpoint contract address
*/functionsetEndpoint(address _lzEndpoint) externalonlyOwner{
_setEndpoint(_lzEndpoint);
}
/**
* @notice Sets the cross-chain relayer contract reference
* @param _lzRelayer The cross-chain relayer contract address
*/functionsetRelayer(address _lzRelayer) externalonlyOwner{
_setRelayer(_lzRelayer);
}
/**
* @notice Sets the validation data
* @param _validation The validation data
*/functionsetValidation(bytesmemory _validation) externalonlyOwner{
_setValidation(_validation);
}
/**
* @notice Source chain tx value estimation
* @param _parameters Gas transfer parameters
* @return lzValue The source chain tx value
*/functionestimateSourceValue(
GasTransferParameters calldata _parameters
) externalviewreturns (uint256 lzValue) {
(lzValue, , ) = _getEndpointData(_parameters, false);
}
/**
* @notice The native token amount cap on the destination chains
* @param _lzChainIds The destination chain identifier array (LayerZero-specific)
* @return The native token amount cap on the destination chains
*/functiondestinationAmountCap(uint16[] calldata _lzChainIds
) externalviewreturns (uint128[] memory) {
uint128[] memory result =newuint128[](_lzChainIds.length);
uint16 lzChainId;
uint16 outboundProofType;
uint128 cap;
address sendLibrary = SendLibraryProvider(lzEndpoint).getSendLibraryAddress(address(this));
for (uint256 index; index < _lzChainIds.length; index++) {
lzChainId = _lzChainIds[index];
outboundProofType = AppConfigProvider(sendLibrary)
.getAppConfig(lzChainId, address(this))
.outboundProofType;
(cap, , ) = ILayerZeroRelayer(lzRelayer).dstConfigLookup(lzChainId, outboundProofType);
result[index] = cap;
}
return result;
}
function_setEndpoint(address _lzEndpoint) private{
AddressHelper.requireContract(_lzEndpoint);
lzEndpoint = _lzEndpoint;
emit SetEndpoint(_lzEndpoint);
}
function_setRelayer(address _lzRelayer) private{
AddressHelper.requireContract(_lzRelayer);
lzRelayer = _lzRelayer;
emit SetRelayer(_lzRelayer);
}
function_setValidation(bytesmemory _validation) private{
(minDstGas, minReserve) =abi.decode(_validation, (uint256, uint256));
}
function_getEndpointData(
GasTransferParameters calldata _parameters,
bool _validate
) privateviewreturns (uint256 lzValue, address dstApp, bytesmemory lzAdapterParameters) {
uint256 dstGas;
(dstApp, dstGas, lzAdapterParameters) = _decodeParameters(_parameters);
(lzValue, ) = ILayerZeroEndpoint(lzEndpoint).estimateFees(
_parameters.lzChainId,
address(this),
LZ_PAYLOAD_NONE,
false,
lzAdapterParameters
);
if (_validate && (dstGas < minDstGas || lzValue + minReserve >msg.value)) {
revert ValidationError();
}
}
function_decodeParameters(
GasTransferParameters calldata _parameters
) privateviewreturns (address dstApp, uint256 dstGas, bytesmemory lzAdapterParameters) {
(dstApp, dstGas) =abi.decode(_parameters.settings, (address, uint256));
lzAdapterParameters =abi.encodePacked(
LZ_ADAPTER_PARAMETERS_VERSION,
dstGas,
_parameters.amount,
_parameters.recipient ==address(0) ? msg.sender : _parameters.recipient
);
}
}
interfaceSendLibraryProvider{
functiongetSendLibraryAddress(address _userApplication
) externalviewreturns (address sendLibraryAddress);
}
interfaceAppConfigProvider{
structApplicationConfiguration {
uint16 inboundProofLibraryVersion;
uint64 inboundBlockConfirmations;
address relayer;
uint16 outboundProofType;
uint64 outboundBlockConfirmations;
address oracle;
}
functiongetAppConfig(uint16 _remoteChainId,
address _userApplicationAddress
) externalviewreturns (ApplicationConfiguration memory);
}
Contract Source Code
File 9 of 13: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)pragmasolidity ^0.8.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.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/function_checkOwner() internalviewvirtual{
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.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 10 of 13: OwnerManageable.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;import { Ownable } from'@openzeppelin/contracts/access/Ownable.sol';
import { Pausable } from'@openzeppelin/contracts/security/Pausable.sol';
import { ITokenBalance } from'../interfaces/ITokenBalance.sol';
import'../helpers/TransferHelper.sol'asTransferHelper;
import'../Constants.sol'asConstants;
/**
* @title OwnerManageable
* @notice OwnerManageable contract
*/contractOwnerManageableisOwnable, Pausable{
/**
* @notice Enter pause state
*/functionpause() externalonlyOwnerwhenNotPaused{
_pause();
}
/**
* @notice Exit pause state
*/functionunpause() externalonlyOwnerwhenPaused{
_unpause();
}
/**
* @notice Performs the token cleanup
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
*/functioncleanup(address _tokenAddress) externalonlyOwner{
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, address(this).balance);
} else {
TransferHelper.safeTransfer(
_tokenAddress,
msg.sender,
ITokenBalance(_tokenAddress).balanceOf(address(this))
);
}
}
/**
* @notice Performs the token cleanup using the provided amount
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @param _tokenAmount The amount of the token
*/functioncleanupWithAmount(address _tokenAddress, uint256 _tokenAmount) externalonlyOwner{
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
function_initOwner(address _owner) internal{
if (_owner != _msgSender() && _owner !=address(0)) {
_transferOwnership(_owner);
}
}
}
Contract Source Code
File 11 of 13: Pausable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/abstractcontractPausableisContext{
/**
* @dev Emitted when the pause is triggered by `account`.
*/eventPaused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/eventUnpaused(address account);
boolprivate _paused;
/**
* @dev Initializes the contract in unpaused state.
*/constructor() {
_paused =false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/modifierwhenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/modifierwhenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/functionpaused() publicviewvirtualreturns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/function_requireNotPaused() internalviewvirtual{
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/function_requirePaused() internalviewvirtual{
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/function_pause() internalvirtualwhenNotPaused{
_paused =true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/function_unpause() internalvirtualwhenPaused{
_paused =false;
emit Unpaused(_msgSender());
}
}
Contract Source Code
File 12 of 13: SystemVersionId.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @title SystemVersionId
* @notice Base contract providing the system version identifier
*/abstractcontractSystemVersionId{
/**
* @dev The system version identifier
*/uint256publicconstant SYSTEM_VERSION_ID =uint256(keccak256('Initial'));
}
Contract Source Code
File 13 of 13: TransferHelper.sol
// SPDX-License-Identifier: AGPL-3.0-onlypragmasolidity 0.8.19;/**
* @notice Emitted when an approval action fails
*/errorSafeApproveError();
/**
* @notice Emitted when a transfer action fails
*/errorSafeTransferError();
/**
* @notice Emitted when a transferFrom action fails
*/errorSafeTransferFromError();
/**
* @notice Emitted when a transfer of the native token fails
*/errorSafeTransferNativeError();
/**
* @notice Safely approve the token to the account
* @param _token The token address
* @param _to The token approval recipient address
* @param _value The token approval amount
*/functionsafeApprove(address _token, address _to, uint256 _value) {
// 0x095ea7b3 is the selector for "approve(address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
/**
* @notice Safely transfer the token to the account
* @param _token The token address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/functionsafeTransfer(address _token, address _to, uint256 _value) {
// 0xa9059cbb is the selector for "transfer(address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
/**
* @notice Safely transfer the token between the accounts
* @param _token The token address
* @param _from The token transfer source address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/functionsafeTransferFrom(address _token, address _from, address _to, uint256 _value) {
// 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
(bool success, bytesmemory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length==0||abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
/**
* @notice Safely transfer the native token to the account
* @param _to The native token transfer recipient address
* @param _value The native token transfer amount
*/functionsafeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(newbytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}