Source Code
Overview
S Balance
S Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
msUSDV2Sonic
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {OFTCoreUpgradeable, OFTUpgradeable} from "../utils/oft/OFTUpgradeable.sol";
import {IOFTCore} from "@layerzerolabs/contracts/token/oft/v1/interfaces/IOFTCore.sol";
import {ImsUSDV2} from "../interfaces/ImsUSDV2.sol";
/**
* @title msUSDV2Sonic
* @author Mainstreet Labs
* @notice The Sonic implementation of msUSDV2, a cross-chain synthetic USD stablecoin built on LayerZero's
* Omnichain Fungible Token (OFT) standard. This contract served as the legacy token which originally served
* as the primary token contract where the underlying collateral is deposited and msUSD tokens are minted through the minter contract.
* This contract in a new upgrade has depracated all minter functionality and now only serves as a satellite token.
* All minting functionality (through the Minter) has been moved to Ethereum.
* @dev This home chain implementation uses a unique Sonic-only msUSDV2 token with minting to allow for the legacy version
* to be safely migrated to a new home-chain. The bridging mechanics have been updated to support the usual mint-and-burn
* on bridge mechanics to serve as a new Satellite token.
* This contract has all the home-chain minting functions, but since the upgrade in November 2025, will serve only as a satellite token.
*
* **Cross-Chain Bridge Mechanism:**
* - Outgoing transfers: `_debitFrom()` burns tokens from account
* - Incoming transfers: `_creditTo()` mints tokens to account
* - LayerZero messaging handles cross-chain communication with satellite contracts
* - Non-blocking message handling with retry capabilities for failed transfers
*
* **Supply Management:**
* - Owner-configurable supply limit to control maximum token circulation
* - Designated minter role for permissioned token issuance from collateral deposits
* - Supply limit enforcement during minting operations
*/
contract msUSDV2Sonic is UUPSUpgradeable, OFTUpgradeable, ImsUSDV2 {
/// @dev Stores the total supply limit. Total Supply cannot exceed this amount.
uint256 public supplyLimit;
/// @dev Stores the address of the `msUSDMinter` contract.
address public minter;
/// @dev Stores the address of the `StakedmsUSD` contract.
address public stakedmsUSD;
/**
* @notice Initializes msUSDV2.
* @param lzEndpoint Local layer zero v1 endpoint address.
*/
constructor(address lzEndpoint) OFTUpgradeable(lzEndpoint) {
_disableInitializers();
}
/**
* @notice Initializes msUSDV2's inherited upgradeables.
* @param owner Initial owner of contract.
* @param name Name of wrapped token.
* @param symbol Symbol of wrapped token.
*/
function initialize(
address owner,
string memory name,
string memory symbol
) external initializer {
__OFT_init(owner, name, symbol);
}
/// @dev Overrides _update from ERC20Upgradeable.
function _update(address from, address to, uint256 amount) internal override {
super._update(from, to, amount);
if (from == address(0) && totalSupply() > supplyLimit) revert SupplyLimitExceeded();
}
/// @dev Allows owner to set a ceiling on msUSD total supply to throttle minting.
function setSupplyLimit(uint256 limit) external onlyOwner {
emit SupplyLimitUpdated(limit);
supplyLimit = limit;
}
/// @dev Allows the owner to update the `minter` state variable.
function setMinter(address newMinter) external onlyOwner {
emit MinterUpdated(newMinter, minter);
minter = newMinter;
}
/// @dev Allows the owner to update the `stakedmsUSD` state variable.
function setStakedmsUSD(address newStakedmsUSD) external onlyOwner {
emit StakedmsUSDUpdated(newStakedmsUSD, stakedmsUSD);
stakedmsUSD = newStakedmsUSD;
}
/// @dev Allows the `minter` to mint more msUSD tokens to a specified `to` address.
function mint(address to, uint256 amount) external {
if (msg.sender != minter && msg.sender != stakedmsUSD) revert NotAuthorized(msg.sender);
_mint(to, amount);
}
/// @dev Burns `amount` tokens from msg.sender.
function burn(uint256 amount) external {
_burn(msg.sender, amount);
}
/// @dev Burns `amount` of tokens from `account`, given approval from `account`.
function burnFrom(address account, uint256 amount) external {
if (account != msg.sender) _spendAllowance(account, msg.sender, amount);
_burn(account, amount);
}
/// @dev Cannot renounce ownership of contract.
function renounceOwnership() public view override onlyOwner {
revert CantRenounceOwnership();
}
/**
* @notice Inherited from UUPSUpgradeable.
*/
function _authorizeUpgrade(address) internal override onlyOwner {}
function sendFrom(
address _from,
uint16 _dstChainId,
bytes calldata _toAddress,
uint256 _amount,
address payable _refundAddress,
address _zroPaymentAddress,
bytes calldata _adapterParams
) public payable override(IOFTCore, OFTCoreUpgradeable) {
_send(
_from,
_dstChainId,
_toAddress,
_amount,
_refundAddress,
_zroPaymentAddress,
_adapterParams
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20, ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IOFT} from "@layerzerolabs/contracts/token/oft/v1/interfaces/IOFT.sol";
import {OFTCoreUpgradeable} from "./OFTCoreUpgradeable.sol";
/**
* @title OFTUpgradeable
* @dev This contract is an upgradable implementation of LayerZero's Omnichain Fungible Tokens (OFT) standard.
* It inherits the core functionalities from OFTCoreUpgradeable and extends it by adding ERC-20 token functionalities.
* This contract is designed to allow the token to be transacted across different blockchains in a seamless manner.
*
* Key methods include `_debitFrom` and `_creditTo`, which are overridden to handle the actual token transactions.
* This contract is also compatible with the ERC-165 standard for contract introspection.
*/
contract OFTUpgradeable is OFTCoreUpgradeable, ERC20Upgradeable, IOFT {
/**
* @param endpoint The address of the LayerZero endpoint.
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(address endpoint) OFTCoreUpgradeable(endpoint) {}
/**
* @dev Initializes the OFT token with a given name and symbol.
* It sets the state within this contract and also initializes the inherited ERC20 token with the given name and
* symbol.
* This function should only be called during the contract initialization phase.
*
* @param initialOwner The address of the initial owner.
* @param name The name of the token.
* @param symbol The symbol of the token.
*/
function __OFT_init(address initialOwner, string memory name, string memory symbol) internal onlyInitializing {
__OFT_init_unchained();
__OFTCore_init(initialOwner);
__ERC20_init(name, symbol);
}
function __OFT_init_unchained() internal onlyInitializing {}
/**
* @dev Implements the ERC165 standard for contract introspection.
* Extends the functionality to include the interface IDs of IOFT and IERC20, alongside the inherited interfaces.
*
* @param interfaceId The interface identifier, as specified in ERC-165.
* @return `true` if the contract implements the interface represented by `interfaceId`, otherwise `false`.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(OFTCoreUpgradeable, IERC165)
returns (bool)
{
return interfaceId == type(IOFT).interfaceId || interfaceId == type(IERC20).interfaceId
|| super.supportsInterface(interfaceId);
}
/**
* @dev Retrieves the address of the OFT token, which is the address of this contract.
* This function is part of the IOFT interface.
*
* @return The address of this OFT token contract.
*/
function token() public view virtual override returns (address) {
return address(this);
}
/**
* @dev Returns the total circulating supply of OFT tokens.
* In this implementation, it's equivalent to the total supply as managed by the ERC20 standard.
* This function is part of the IOFT interface.
*
* @return The total circulating supply of OFT tokens.
*/
function circulatingSupply() public view virtual override returns (uint256) {
return totalSupply();
}
/**
* @dev Handles the token debit operation when sending tokens to another chain.
* Burns the specified amount of tokens from the sender's account.
*
* @param from The address of the token holder.
* @param amount The amount of tokens to be debited (burned).
* @return The actual amount of tokens that were debited.
*/
function _debitFrom(address from, uint16, bytes memory, uint256 amount)
internal
virtual
override
returns (uint256)
{
address spender = _msgSender();
if (from != spender) _spendAllowance(from, spender, amount);
_burn(from, amount);
return amount;
}
/**
* @dev Handles the token credit operation when receiving tokens from another chain.
* Mints the specified amount of tokens to the recipient's account.
*
* @param toAddress The address of the recipient.
* @param amount The amount of tokens to be credited (minted).
* @return The actual amount of tokens that were credited.
*/
function _creditTo(uint16, address toAddress, uint256 amount) internal virtual override returns (uint256) {
_mint(toAddress, amount);
return amount;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @dev Interface of the IOFT core standard
*/
interface IOFTCore is IERC165 {
/**
* @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
* _dstChainId - L0 defined chain id to send tokens too
* _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
* _amount - amount of the tokens to transfer
* _useZro - indicates to use zro to pay L0 fees
* _adapterParam - flexible bytes array to indicate messaging adapter services in L0
*/
function estimateSendFee(uint16 _dstChainId, bytes calldata _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
/**
* @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
* `_from` the owner of token
* `_dstChainId` the destination chain identifier
* `_toAddress` can be any size depending on the `dstChainId`.
* `_amount` the quantity of tokens in wei
* `_refundAddress` the address LayerZero refunds if too much message fee is sent
* `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
* `_adapterParams` is a flexible bytes array to indicate messaging adapter services
*/
function sendFrom(address _from, uint16 _dstChainId, bytes calldata _toAddress, uint _amount, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
/**
* @dev returns the circulating amount of tokens on current chain
*/
function circulatingSupply() external view returns (uint);
/**
* @dev returns the address of the ERC20 token
*/
function token() external view returns (address);
/**
* @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
* `_nonce` is the outbound nonce
*/
event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint _amount);
/**
* @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.
* `_nonce` is the inbound nonce.
*/
event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount);
event SetUseCustomAdapterParams(bool _useCustomAdapterParams);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ImsUSDV2 is IERC20 {
/// @dev This event is fired when the minter changes.
event MinterUpdated(address indexed newMinter, address indexed oldMinter);
/// @dev This event is emitted when the supply limit is updated.
event SupplyLimitUpdated(uint256 indexed newSupplyLimit);
/// @dev This event is emitted when the stakedmsUSD address is updated.
event StakedmsUSDUpdated(address indexed newStakedmsUSD, address indexed oldStakedmsUSD);
/// @dev Error emitted when totalSupply exceeds `supplyLimit`.
error SupplyLimitExceeded();
/// @dev Zero address not allowed.
error ZeroAddressException();
/// @dev It's not possible to renounce the ownership.
error CantRenounceOwnership();
/// @dev Emitted when msg.sender is not authorized.
error NotAuthorized(address account);
/// @dev Allows the `minter` to mint more msUSD tokens to a specified `to` address.
function mint(address _to, uint256 _amount) external;
/// @dev Burns `amount` tokens from msg.sender.
function burn(uint256 _amount) external;
/// @dev Burns `amount` of tokens from `account`, given approval from `account`.
function burnFrom(address account, uint256 amount) external;
/// @dev Allows the owner to update the `minter` state variable.
function setMinter(address newMinter) external;
/// @dev Allows owner to set a ceiling on msUSD total supply to throttle minting.
function setSupplyLimit(uint256 limit) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {
/// @custom:storage-location erc7201:openzeppelin.storage.ERC20
struct ERC20Storage {
mapping(address account => uint256) _balances;
mapping(address account => mapping(address spender => uint256)) _allowances;
uint256 _totalSupply;
string _name;
string _symbol;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
function _getERC20Storage() private pure returns (ERC20Storage storage $) {
assembly {
$.slot := ERC20StorageLocation
}
}
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC20Storage storage $ = _getERC20Storage();
$._name = name_;
$._symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
return $._name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
return $._symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
ERC20Storage storage $ = _getERC20Storage();
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
$._totalSupply += value;
} else {
uint256 fromBalance = $._balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
$._balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
$._totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
$._balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
ERC20Storage storage $ = _getERC20Storage();
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
$._allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "./IOFTCore.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @dev Interface of the OFT standard
*/
interface IOFT is IOFTCore, IERC20 {
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IOFTCore} from "@layerzerolabs/contracts/token/oft/v1/interfaces/IOFTCore.sol";
import {BytesLib} from "@layerzerolabs/contracts/libraries/BytesLib.sol";
import {NonblockingLzAppUpgradeable} from "../lzApp/NonblockingLzAppUpgradeable.sol";
import {IOFTSubscriber} from "../../interfaces/IOFTSubscriber.sol";
/**
* @title OFTCoreUpgradeable
* @dev This contract extends NonblockingLzAppUpgradeable to provide a core implementation for OFT (On-Chain Forwarding
* Token). It introduces packet types, custom adapter params, and methods for sending and receiving tokens across
* chains.
*
* This contract is intended to be inherited by other contracts that implement specific token logic.
*
* Packet Types:
* - PT_SEND: Packet type for sending tokens. Value is 0.
*
* Custom Adapter Params:
* - The contract allows for the use of custom adapter parameters which affect the gas usage for cross-chain operations.
*
* Storage:
* - useCustomAdapterParams: A flag to indicate whether to use custom adapter parameters.
*/
abstract contract OFTCoreUpgradeable is NonblockingLzAppUpgradeable, ERC165, IOFTCore {
using BytesLib for bytes;
uint256 public constant NO_EXTRA_GAS = 0;
// packet type
uint16 public constant PT_SEND = 0;
/// @custom:storage-location erc7201:layerzero.storage.OFTCore
struct OFTCoreStorage {
bool useCustomAdapterParams;
}
// keccak256(abi.encode(uint256(keccak256("layerzero.storage.OFTCore")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OFTCoreStorageLocation = 0x822492242235517548c4a8cf040400e3c0daf5b82af652ed16dce4fa3ae72800;
function _getOFTCoreStorage() private pure returns (OFTCoreStorage storage $) {
// slither-disable-next-line assembly
assembly {
$.slot := OFTCoreStorageLocation
}
}
/**
* @param endpoint The address of the LayerZero endpoint.
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(address endpoint) NonblockingLzAppUpgradeable(endpoint) {}
/**
* @dev Initializes the contract state for `OFTCoreUpgradeable`.
* Calls the initialization functions of parent contracts.
*
* @param initialOwner The address of the initial owner.
*/
function __OFTCore_init(address initialOwner) internal onlyInitializing {
__OFTCore_init_unchained();
__NonblockingLzApp_init(initialOwner);
}
function __OFTCore_init_unchained() internal onlyInitializing {}
/**
* @dev Checks if the contract supports a given interface ID.
* Overrides the implementation in ERC165 to include support for IOFTCore.
*
* @param interfaceId The ID of the interface to check.
* @return bool `true` if the contract supports the given interface ID, `false` otherwise.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Estimates the fee required for sending tokens to a different chain.
* This function is part of the IOFTCore interface.
*
* @param dstChainId The ID of the destination chain.
* @param toAddress The address to which the tokens will be sent on the destination chain.
* @param amount The amount of tokens to send.
* @param useZro Flag indicating whether to use ZRO for payment.
* @param adapterParams Additional parameters for the adapter.
* @return nativeFee The estimated native chain fee.
* @return zroFee The estimated ZRO fee.
*/
function estimateSendFee(
uint16 dstChainId,
bytes calldata toAddress,
uint256 amount,
bool useZro,
bytes calldata adapterParams
) public view virtual override returns (uint256 nativeFee, uint256 zroFee) {
// mock the payload for sendFrom()
bytes memory payload = abi.encode(PT_SEND, toAddress, amount);
return lzEndpoint.estimateFees(dstChainId, address(this), payload, useZro, adapterParams);
}
/**
* @dev Sends tokens from a given address to a destination address on another chain.
* This function is part of the IOFTCore interface.
*
* @param from The address from which tokens will be sent.
* @param dstChainId The ID of the destination chain.
* @param toAddress The address on the destination chain to which tokens will be sent.
* @param amount The amount of tokens to send.
* @param refundAddress The address where any excess native fee will be refunded.
* @param zroPaymentAddress The address used for ZRO payments, if applicable.
* @param adapterParams Additional parameters for the adapter.
*/
function sendFrom(
address from,
uint16 dstChainId,
bytes calldata toAddress,
uint256 amount,
address payable refundAddress,
address zroPaymentAddress,
bytes calldata adapterParams
) public payable virtual override {
_send(from, dstChainId, toAddress, amount, refundAddress, zroPaymentAddress, adapterParams);
}
/**
* @dev Toggles the use of custom adapter parameters.
* When enabled, the contract will check gas limits based on the provided adapter parameters.
*
* @param useCustomAdapterParams Flag indicating whether to use custom adapter parameters.
*/
function setUseCustomAdapterParams(bool useCustomAdapterParams) public virtual onlyOwner {
OFTCoreStorage storage $ = _getOFTCoreStorage();
$.useCustomAdapterParams = useCustomAdapterParams;
emit SetUseCustomAdapterParams(useCustomAdapterParams);
}
/**
* @dev Handles incoming messages from other chains in a non-blocking fashion.
* This function overrides the abstract implementation in NonblockingLzAppUpgradeable.
*
* @param srcChainId The ID of the source chain.
* @param srcAddress The address on the source chain from which the message originated.
* @param nonce A unique identifier for the message.
* @param payload The actual data sent from the source chain.
*/
function _nonblockingLzReceive(uint16 srcChainId, bytes memory srcAddress, uint64 nonce, bytes memory payload)
internal
virtual
override
{
uint16 packetType;
// slither-disable-next-line assembly
assembly {
packetType := mload(add(payload, 32))
}
if (packetType == PT_SEND) {
_sendAck(srcChainId, srcAddress, nonce, payload);
} else {
revert("OFTCore: unknown packet type");
}
}
/**
* @dev Performs the actual sending of tokens to a destination chain.
* This internal function is called by the public wrapper `sendFrom`.
*
* @param from The address from which tokens are sent.
* @param dstChainId The ID of the destination chain.
* @param toAddress The address on the destination chain where tokens will be sent.
* @param amount The amount of tokens to send.
* @param refundAddress The address for refunding any excess native fee.
* @param zroPaymentAddress The address for ZRO payment, if applicable.
* @param adapterParams Additional parameters for the adapter.
*/
function _send(
address from,
uint16 dstChainId,
bytes memory toAddress,
uint256 amount,
address payable refundAddress,
address zroPaymentAddress,
bytes memory adapterParams
) internal virtual {
_checkAdapterParams(dstChainId, PT_SEND, adapterParams, NO_EXTRA_GAS);
amount = _debitFrom(from, dstChainId, toAddress, amount);
bytes memory lzPayload = abi.encode(PT_SEND, toAddress, amount);
_lzSend(dstChainId, lzPayload, refundAddress, zroPaymentAddress, adapterParams, msg.value);
emit SendToChain(dstChainId, from, toAddress, amount);
}
/**
* @dev Acknowledges the reception of tokens sent from another chain.
* This function is called internally when a PT_SEND packet type is received.
*
* @param srcChainId The ID of the source chain from which the tokens were sent.
* @param payload The payload containing the details of the sent tokens.
*/
function _sendAck(uint16 srcChainId, bytes memory, uint64, bytes memory payload) internal virtual {
(, bytes memory toAddressBytes, uint256 amount) = abi.decode(payload, (uint16, bytes, uint256));
address to = toAddressBytes.toAddress(0);
amount = _creditTo(srcChainId, to, amount);
emit ReceiveFromChain(srcChainId, to, amount);
}
/**
* @dev Validates the adapter parameters for sending tokens.
* This function can be configured to either enforce a gas limit or to accept custom parameters.
*
* @param dstChainId The ID of the destination chain.
* @param pkType The packet type of the message.
* @param adapterParams The additional parameters for the adapter.
* @param extraGas The extra gas that may be needed for execution.
*/
function _checkAdapterParams(uint16 dstChainId, uint16 pkType, bytes memory adapterParams, uint256 extraGas)
internal
virtual
{
OFTCoreStorage storage $ = _getOFTCoreStorage();
if ($.useCustomAdapterParams) {
_checkGasLimit(dstChainId, pkType, adapterParams, extraGas);
} else {
require(adapterParams.length == 0, "OFTCore: _adapterParams must be empty.");
}
}
/**
* @dev Debits an amount of tokens from the specified address.
* This is an internal function that should be overridden to handle the actual token transfer logic.
*
* @param from The address from which tokens will be debited.
* @param dstChainId The ID of the destination chain.
* @param toAddress The encoded destination address on the target chain.
* @param amount The amount of tokens to debit.
* @return The final amount of tokens that were debited. This allows for potential adjustments.
*/
function _debitFrom(address from, uint16 dstChainId, bytes memory toAddress, uint256 amount)
internal
virtual
returns (uint256);
/**
* @dev Credits an amount of tokens to a specific address.
* This is an internal function that should be overridden to handle the actual token crediting logic.
*
* @param srcChainId The ID of the source chain from which the tokens were sent.
* @param toAddress The address to which tokens will be credited.
* @param amount The amount of tokens to credit.
* @return The final amount of tokens that were credited. This allows for potential adjustments.
*/
function _creditTo(uint16 srcChainId, address toAddress, uint256 amount) internal virtual returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask))) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint _start, uint _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint _start) internal pure returns (uint) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ExcessivelySafeCall} from "@layerzerolabs/contracts/libraries/ExcessivelySafeCall.sol";
import {LzAppUpgradeable} from "./LzAppUpgradeable.sol";
/**
* @title Nonblocking LayerZero Application
* @dev This contract extends LzAppUpgradeable and modifies its behavior to be non-blocking. Failed messages are caught
* and stored for future retries, ensuring that the message channel remains unblocked. This contract serves as an
* abstract base class and should be extended by specific implementations.
*
* Note: If the `srcAddress` is not configured properly, it will still block the message pathway from (`srcChainId`,
* `srcAddress`).
*/
abstract contract NonblockingLzAppUpgradeable is LzAppUpgradeable {
using ExcessivelySafeCall for address;
event MessageFailed(uint16 srcChainId, bytes srcAddress, uint64 nonce, bytes payload, bytes reason);
event RetryMessageSuccess(uint16 srcChainId, bytes srcAddress, uint64 nonce, bytes32 payloadHash);
/// @custom:storage-location erc7201:layerzero.storage.NonblockingLzApp
struct NonblockingLzAppStorage {
mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) failedMessages;
}
// keccak256(abi.encode(uint256(keccak256("layerzero.storage.NonblockingLzApp")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant NonblockingLzAppStorageLocation =
0xe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d8600;
function _getNonblockingLzAppStorage() private pure returns (NonblockingLzAppStorage storage $) {
// slither-disable-next-line assembly
assembly {
$.slot := NonblockingLzAppStorageLocation
}
}
/**
* @param endpoint The address of the LayerZero endpoint contract.
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(address endpoint) LzAppUpgradeable(endpoint) {}
/**
* @dev Initializes the contract, setting the initial owner and endpoint addresses.
* Also chains the initialization process with the base `LzAppUpgradeable` contract.
*
* Requirements:
* - Can only be called during contract initialization.
*
* @param initialOwner The address that will initially own the contract.
*/
function __NonblockingLzApp_init(address initialOwner) internal onlyInitializing {
__NonblockingLzApp_init_unchained();
__LzApp_init(initialOwner);
}
function __NonblockingLzApp_init_unchained() internal onlyInitializing {}
/**
* @dev Retrieves the hash of the payload of a failed message for a given source chain, source address, and nonce.
*
* @param srcChainId The ID of the source chain where the message originated.
* @param srcAddress The address on the source chain where the message originated.
* @param nonce The nonce of the failed message.
* @return payloadHash The hash of the payload of the failed message.
*/
function failedMessages(uint16 srcChainId, bytes calldata srcAddress, uint64 nonce)
external
view
returns (bytes32 payloadHash)
{
NonblockingLzAppStorage storage $ = _getNonblockingLzAppStorage();
return $.failedMessages[srcChainId][srcAddress][nonce];
}
/**
* @dev Internal function that receives LayerZero messages and attempts to process them in a non-blocking manner.
* If processing fails, the message is stored for future retries.
*
* @param srcChainId The ID of the source chain where the message originated.
* @param srcAddress The address on the source chain where the message originated.
* @param nonce The nonce of the message.
* @param payload The payload of the message.
*/
function _blockingLzReceive(uint16 srcChainId, bytes memory srcAddress, uint64 nonce, bytes memory payload)
internal
virtual
override
{
(bool success, bytes memory reason) = address(this).excessivelySafeCall(
gasleft(),
150,
abi.encodeWithSelector(this.nonblockingLzReceive.selector, srcChainId, srcAddress, nonce, payload)
);
// try-catch all errors/exceptions
if (!success) {
_storeFailedMessage(srcChainId, srcAddress, nonce, payload, reason);
}
}
/**
* @dev Internal function to store the details of a failed message for future retries.
*
* @param srcChainId The ID of the source chain where the message originated.
* @param srcAddress The address on the source chain where the message originated.
* @param nonce The nonce of the failed message.
* @param payload The payload of the failed message.
* @param reason The reason for the message's failure.
*/
function _storeFailedMessage(
uint16 srcChainId,
bytes memory srcAddress,
uint64 nonce,
bytes memory payload,
bytes memory reason
) internal virtual {
NonblockingLzAppStorage storage $ = _getNonblockingLzAppStorage();
$.failedMessages[srcChainId][srcAddress][nonce] = keccak256(payload);
emit MessageFailed(srcChainId, srcAddress, nonce, payload, reason);
}
/**
* @dev Public wrapper function for handling incoming LayerZero messages in a non-blocking manner.
* It internally calls the `_nonblockingLzReceive` function, which should be overridden in derived contracts.
*
* Requirements:
* - The caller must be the contract itself.
*
* @param srcChainId The ID of the source chain where the message originated.
* @param srcAddress The address on the source chain where the message originated.
* @param nonce The nonce of the message.
* @param payload The payload of the message.
*/
function nonblockingLzReceive(uint16 srcChainId, bytes calldata srcAddress, uint64 nonce, bytes calldata payload)
public
virtual
{
// only internal transaction
require(_msgSender() == address(this), "NonblockingLzApp: caller must be LzApp");
_nonblockingLzReceive(srcChainId, srcAddress, nonce, payload);
}
/**
* @dev Internal function that should be overridden in derived contracts to implement the logic
* for processing incoming LayerZero messages in a non-blocking manner.
*
* @param srcChainId The ID of the source chain where the message originated.
* @param srcAddress The address on the source chain where the message originated.
* @param nonce The nonce of the message.
* @param payload The payload of the message.
*/
function _nonblockingLzReceive(uint16 srcChainId, bytes memory srcAddress, uint64 nonce, bytes memory payload)
internal
virtual;
/**
* @dev Allows for the manual retry of a previously failed message.
*
* Requirements:
* - There must be a stored failed message matching the provided parameters.
* - The payload hash must match the stored failed message.
*
* @param srcChainId The ID of the source chain where the failed message originated.
* @param srcAddress The address on the source chain where the failed message originated.
* @param nonce The nonce of the failed message.
* @param payload The payload of the failed message.
*/
function retryMessage(uint16 srcChainId, bytes calldata srcAddress, uint64 nonce, bytes calldata payload)
public
payable
virtual
{
NonblockingLzAppStorage storage $ = _getNonblockingLzAppStorage();
mapping(uint64 => bytes32) storage _failedMessages = $.failedMessages[srcChainId][srcAddress];
// get the payload hash value
bytes32 payloadHash = _failedMessages[nonce];
// assert there is message to retry
require(payloadHash != bytes32(0), "NonblockingLzApp: no stored message");
require(keccak256(payload) == payloadHash, "NonblockingLzApp: invalid payload");
// clear the stored message
_failedMessages[nonce] = bytes32(0);
// execute the message. revert if it fails again
_nonblockingLzReceive(srcChainId, srcAddress, nonce, payload);
emit RetryMessageSuccess(srcChainId, srcAddress, nonce, payloadHash);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
/**
* @dev Interface of the OFT subscriber
*/
interface IOFTSubscriber {
/**
* @notice Notifies the contract about a token credit from a source chain.
* @dev This function allows external systems to inform the contract about credited tokens.
* @param srcChainId Chain ID of the source chain.
* @param initiator Address of the initiator on the source chain.
* @param sender The address on the source chain from which the tokens were sent.
* @param token Address of the credited token.
* @param amount Amount of tokens credited.
*/
function notifyCredit(uint16 srcChainId, address initiator, address sender, address token, uint256 amount)
external;
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.7.6;
library ExcessivelySafeCall {
uint constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @notice Use when you _really_ really _really_ don't trust the called
/// contract. This prevents the called contract from causing reversion of
/// the caller in as many ways as we can.
/// @dev The main difference between this and a solidity low-level call is
/// that we limit the number of bytes that the callee can cause to be
/// copied to caller memory. This prevents stupid things like malicious
/// contracts returning 10,000,000 bytes causing a local OOG when copying
/// to memory.
/// @param _target The address to call
/// @param _gas The amount of gas to forward to the remote contract
/// @param _maxCopy The maximum number of bytes of returndata to copy
/// to memory.
/// @param _calldata The data to send to the remote contract
/// @return success and returndata, as `.call()`. Returndata is capped to
/// `_maxCopy` bytes.
function excessivelySafeCall(
address _target,
uint _gas,
uint16 _maxCopy,
bytes memory _calldata
) internal returns (bool, bytes memory) {
// set up for assembly call
uint _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly {
_success := call(
_gas, // gas
_target, // recipient
0, // ether value
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
// limit our copy to 256 bytes
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytes
mstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/// @notice Use when you _really_ really _really_ don't trust the called
/// contract. This prevents the called contract from causing reversion of
/// the caller in as many ways as we can.
/// @dev The main difference between this and a solidity low-level call is
/// that we limit the number of bytes that the callee can cause to be
/// copied to caller memory. This prevents stupid things like malicious
/// contracts returning 10,000,000 bytes causing a local OOG when copying
/// to memory.
/// @param _target The address to call
/// @param _gas The amount of gas to forward to the remote contract
/// @param _maxCopy The maximum number of bytes of returndata to copy
/// to memory.
/// @param _calldata The data to send to the remote contract
/// @return success and returndata, as `.call()`. Returndata is capped to
/// `_maxCopy` bytes.
function excessivelySafeStaticCall(
address _target,
uint _gas,
uint16 _maxCopy,
bytes memory _calldata
) internal view returns (bool, bytes memory) {
// set up for assembly call
uint _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly {
_success := staticcall(
_gas, // gas
_target, // recipient
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
// limit our copy to 256 bytes
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
// Store the length of the copied bytes
mstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
/**
* @notice Swaps function selectors in encoded contract calls
* @dev Allows reuse of encoded calldata for functions with identical
* argument types but different names. It simply swaps out the first 4 bytes
* for the new selector. This function modifies memory in place, and should
* only be used with caution.
* @param _newSelector The new 4-byte selector
* @param _buf The encoded contract args
*/
function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {
require(_buf.length >= 4);
uint _mask = LOW_28_MASK;
assembly {
// load the first word of
let _word := mload(add(_buf, 0x20))
// mask out the top 4 bytes
// /x
_word := and(_word, _mask)
_word := or(_newSelector, _word)
mstore(add(_buf, 0x20), _word)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ILayerZeroReceiver} from "@layerzerolabs/contracts/lzApp/interfaces/ILayerZeroReceiver.sol";
import {ILayerZeroUserApplicationConfig} from "@layerzerolabs/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol";
import {ILayerZeroEndpoint} from "@layerzerolabs/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol";
import {BytesLib} from "@layerzerolabs/contracts/libraries/BytesLib.sol";
/**
* @title LzAppUpgradeable
* @dev This is a generic implementation of LzReceiver, designed for LayerZero cross-chain communication.
*
* The contract inherits from `OwnableUpgradeable` and implements `ILayerZeroReceiver` and
* `ILayerZeroUserApplicationConfig` interfaces. It provides functionality for setting and managing trusted remote
* chains and their corresponding paths, configuring minimum destination gas, payload size limitations, and more.
*
* The contract uses a custom storage location `LzAppStorage`, which includes various mappings and state variables such
* as `trustedRemoteLookup`, `minDstGasLookup`, and `payloadSizeLimitLookup`.
*
* Events:
* - `SetPrecrime(address)`: Emitted when the precrime address is set.
* - `SetTrustedRemote(uint16, bytes)`: Emitted when a trusted remote chain is set with its path.
* - `SetTrustedRemoteAddress(uint16, bytes)`: Emitted when a trusted remote chain is set with its address.
* - `SetMinDstGas(uint16, uint16, uint256)`: Emitted when minimum destination gas is set for a chain and packet type.
*
* Initialization:
* The contract should be initialized by calling `__LzApp_init` function.
*
* Permissions:
* Most administrative tasks require the sender to be the contract's owner.
*
* Note:
* The contract includes the Checks-Effects-Interactions pattern and optimizes for gas-efficiency wherever applicable.
*/
abstract contract LzAppUpgradeable is OwnableUpgradeable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
using BytesLib for bytes;
// ua can not send payload larger than this by default, but it can be changed by the ua owner
uint256 public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10_000;
event SetPrecrime(address precrime);
event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint256 _minDstGas);
/// @custom:storage-location erc7201:layerzero.storage.LzApp
struct LzAppStorage {
mapping(uint16 => bytes) trustedRemoteLookup;
mapping(uint16 => mapping(uint16 => uint256)) minDstGasLookup;
mapping(uint16 => uint256) payloadSizeLimitLookup;
address precrime;
}
// keccak256(abi.encode(uint256(keccak256("layerzero.storage.LzApp")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant LzAppStorageLocation = 0x111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b00;
function _getLzAppStorage() private pure returns (LzAppStorage storage $) {
// slither-disable-next-line assembly
assembly {
$.slot := LzAppStorageLocation
}
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
ILayerZeroEndpoint public immutable lzEndpoint;
/**
* @param endpoint Address of the LayerZero endpoint contract.
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(address endpoint) {
lzEndpoint = ILayerZeroEndpoint(endpoint);
}
/**
* @dev Initializes the contract with the given `initialOwner`.
*
* Requirements:
* - The function should only be called during the initialization process.
*
* @param initialOwner Address of the initial owner of the contract.
*/
function __LzApp_init(address initialOwner) internal onlyInitializing {
__LzApp_init_unchained();
__Ownable_init(initialOwner);
}
function __LzApp_init_unchained() internal onlyInitializing {}
/**
* @dev Returns the trusted path for a given remote chain ID.
*
* @param remoteChainId The ID of the remote chain to query for a trusted path.
* @return path Bytes representation of the trusted path for the specified remote chain ID.
*/
function trustedRemoteLookup(uint16 remoteChainId) external view returns (bytes memory path) {
LzAppStorage storage $ = _getLzAppStorage();
path = $.trustedRemoteLookup[remoteChainId];
}
/**
* @dev Returns the minimum gas required for a given destination chain ID and packet type.
*
* @param dstChainId The ID of the destination chain to query for a minimum gas limit.
* @param packetType The type of packet for which the minimum gas limit is to be fetched.
* @return minGas The minimum gas limit required for the specified destination chain ID and packet type.
*/
function minDstGasLookup(uint16 dstChainId, uint16 packetType) external view returns (uint256 minGas) {
LzAppStorage storage $ = _getLzAppStorage();
minGas = $.minDstGasLookup[dstChainId][packetType];
}
/**
* @dev Returns the payload size limit for a given destination chain ID.
*
* @param dstChainId The ID of the destination chain to query for a payload size limit.
* @return size The maximum allowable payload size in bytes for the specified destination chain ID.
*/
function payloadSizeLimitLookup(uint16 dstChainId) external view returns (uint256 size) {
LzAppStorage storage $ = _getLzAppStorage();
size = $.payloadSizeLimitLookup[dstChainId];
}
/**
* @dev Returns the address of the precrime contract.
*
* @return _precrime The address of the precrime contract.
*/
function precrime() external view returns (address _precrime) {
LzAppStorage storage $ = _getLzAppStorage();
_precrime = $.precrime;
}
/**
* @dev Handles incoming LayerZero messages from a source chain.
* This function must be called by the LayerZero endpoint and validates the source of the message.
*
* Requirements:
* - Caller must be the LayerZero endpoint.
* - Source address must be a trusted remote address.
*
* @param srcChainId The ID of the source chain from which the message is sent.
* @param srcAddress The address on the source chain that is sending the message.
* @param nonce A unique identifier for the message.
* @param payload The actual data payload of the message.
*/
function lzReceive(uint16 srcChainId, bytes calldata srcAddress, uint64 nonce, bytes calldata payload)
public
virtual
override
{
LzAppStorage storage $ = _getLzAppStorage();
// lzReceive must be called by the endpoint for security
require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");
bytes memory trustedRemote = $.trustedRemoteLookup[srcChainId];
// if will still block the message pathway from (srcChainId, srcAddress). should not receive message from
// untrusted remote.
require(
srcAddress.length == trustedRemote.length && trustedRemote.length != 0
&& keccak256(srcAddress) == keccak256(trustedRemote),
"LzApp: invalid source sending contract"
);
_blockingLzReceive(srcChainId, srcAddress, nonce, payload);
}
/**
* @dev Internal function that handles incoming LayerZero messages in a blocking manner.
* This is an abstract function and should be implemented by derived contracts.
*
* @param srcChainId The ID of the source chain from which the message is sent.
* @param srcAddress The address on the source chain that is sending the message.
* @param nonce A unique identifier for the message.
* @param payload The actual data payload of the message.
*/
function _blockingLzReceive(uint16 srcChainId, bytes memory srcAddress, uint64 nonce, bytes memory payload)
internal
virtual;
/**
* @dev Internal function to send a LayerZero message to a destination chain.
* It performs a series of validations before sending the message.
*
* Requirements:
* - Destination chain must be a trusted remote.
* - Payload size must be within the configured limit.
*
* @param dstChainId The ID of the destination chain.
* @param payload The actual data payload to be sent.
* @param refundAddress The address to which any refunds should be sent.
* @param zroPaymentAddress The address for the ZRO token payment.
* @param adapterParams Additional parameters required for the adapter.
* @param nativeFee The native fee to be sent along with the message.
*/
function _lzSend(
uint16 dstChainId,
bytes memory payload,
address payable refundAddress,
address zroPaymentAddress,
bytes memory adapterParams,
uint256 nativeFee
) internal virtual {
LzAppStorage storage $ = _getLzAppStorage();
bytes memory trustedRemote = $.trustedRemoteLookup[dstChainId];
require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
_checkPayloadSize(dstChainId, payload.length);
lzEndpoint.send{value: nativeFee}(
dstChainId, trustedRemote, payload, refundAddress, zroPaymentAddress, adapterParams
);
}
/**
* @dev Internal function to validate if the provided gas limit meets the minimum requirement for a given packet
* type and destination chain.
*
* Requirements:
* - The minimum destination gas limit must be set for the given packet type and destination chain.
* - Provided gas limit should be greater than or equal to the sum of the minimum gas limit and any extra gas.
*
* @param dstChainId The ID of the destination chain.
* @param packetType The type of the packet being sent.
* @param adapterParams Additional parameters required for the adapter.
* @param extraGas Extra gas to be added to the minimum required gas.
*/
function _checkGasLimit(uint16 dstChainId, uint16 packetType, bytes memory adapterParams, uint256 extraGas)
internal
view
virtual
{
LzAppStorage storage $ = _getLzAppStorage();
uint256 providedGasLimit = _getGasLimit(adapterParams);
uint256 minGasLimit = $.minDstGasLookup[dstChainId][packetType];
require(minGasLimit != 0, "LzApp: minGasLimit not set");
require(providedGasLimit >= minGasLimit + extraGas, "LzApp: gas limit is too low");
}
/**
* @dev Internal function to extract the gas limit from the adapter parameters.
*
* Requirements:
* - The `adapterParams` must be at least 34 bytes long to contain the gas limit.
*
* @param _adapterParams The adapter parameters from which the gas limit is to be extracted.
* @return gasLimit The extracted gas limit.
*/
function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint256 gasLimit) {
require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
// slither-disable-next-line assembly
assembly {
gasLimit := mload(add(_adapterParams, 34))
}
}
/**
* @dev Internal function to validate the size of the payload against the configured limit for a given destination
* chain.
*
* Requirements:
* - Payload size must be less than or equal to the configured size limit for the given destination chain.
*
* @param _dstChainId The ID of the destination chain.
* @param _payloadSize The size of the payload in bytes.
*/
function _checkPayloadSize(uint16 _dstChainId, uint256 _payloadSize) internal view virtual {
LzAppStorage storage $ = _getLzAppStorage();
uint256 payloadSizeLimit = $.payloadSizeLimitLookup[_dstChainId];
if (payloadSizeLimit == 0) {
// use default if not set
payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;
}
require(_payloadSize <= payloadSizeLimit, "LzApp: payload size is too large");
}
/**
* @dev Retrieves the configuration of the LayerZero user application for a given version, chain ID, and config
* type.
*
* @param version The version for which the configuration is to be fetched.
* @param chainId The ID of the chain for which the configuration is needed.
* @param configType The type of the configuration to be retrieved.
* @return The bytes representation of the configuration.
*/
function getConfig(uint16 version, uint16 chainId, address, uint256 configType)
external
view
returns (bytes memory)
{
return lzEndpoint.getConfig(version, chainId, address(this), configType);
}
/**
* @dev Sets the configuration of the LayerZero user application for a given version, chain ID, and config type.
*
* Requirements:
* - Only the owner can set the configuration.
*
* @param version The version for which the configuration is to be set.
* @param chainId The ID of the chain for which the configuration is being set.
* @param configType The type of the configuration to be set.
* @param config The actual configuration data in bytes format.
*/
function setConfig(uint16 version, uint16 chainId, uint256 configType, bytes calldata config)
external
override
onlyOwner
{
lzEndpoint.setConfig(version, chainId, configType, config);
}
/**
* @dev Sets the version to be used for sending LayerZero messages.
*
* Requirements:
* - Only the owner can set the send version.
*
* @param version The version to be set for sending messages.
*/
function setSendVersion(uint16 version) external override onlyOwner {
lzEndpoint.setSendVersion(version);
}
/**
* @dev Sets the version to be used for receiving LayerZero messages.
*
* Requirements:
* - Only the owner can set the receive version.
*
* @param version The version to be set for receiving messages.
*/
function setReceiveVersion(uint16 version) external override onlyOwner {
lzEndpoint.setReceiveVersion(version);
}
/**
* @dev Resumes the reception of LayerZero messages from a specific source chain and address.
*
* Requirements:
* - Only the owner can force the resumption of message reception.
*
* @param srcChainId The ID of the source chain from which message reception is to be resumed.
* @param srcAddress The address on the source chain for which message reception is to be resumed.
*/
function forceResumeReceive(uint16 srcChainId, bytes calldata srcAddress) external override onlyOwner {
lzEndpoint.forceResumeReceive(srcChainId, srcAddress);
}
/**
* @dev Sets the trusted path for cross-chain communication with a specified remote chain.
*
* Requirements:
* - Only the owner can set the trusted path.
*
* @param remoteChainId The ID of the remote chain for which the trusted path is being set.
* @param path The trusted path encoded as bytes.
*/
function setTrustedRemote(uint16 remoteChainId, bytes calldata path) external onlyOwner {
LzAppStorage storage $ = _getLzAppStorage();
$.trustedRemoteLookup[remoteChainId] = path;
emit SetTrustedRemote(remoteChainId, path);
}
/**
* @dev Sets the trusted remote address for cross-chain communication with a specified remote chain.
* The function also automatically appends the contract's own address to the path.
*
* Requirements:
* - Only the owner can set the trusted remote address.
*
* @param remoteChainId The ID of the remote chain for which the trusted address is being set.
* @param remoteAddress The trusted remote address encoded as bytes.
*/
function setTrustedRemoteAddress(uint16 remoteChainId, bytes calldata remoteAddress) external onlyOwner {
LzAppStorage storage $ = _getLzAppStorage();
$.trustedRemoteLookup[remoteChainId] = abi.encodePacked(remoteAddress, address(this));
emit SetTrustedRemoteAddress(remoteChainId, remoteAddress);
}
/**
* @dev Retrieves the trusted remote address for a given remote chain.
*
* Requirements:
* - A trusted path record must exist for the specified remote chain.
*
* @param remoteChainId The ID of the remote chain for which the trusted address is needed.
* @return The trusted remote address encoded as bytes.
*/
function getTrustedRemoteAddress(uint16 remoteChainId) external view returns (bytes memory) {
LzAppStorage storage $ = _getLzAppStorage();
bytes memory path = $.trustedRemoteLookup[remoteChainId];
require(path.length != 0, "LzApp: no trusted path record");
return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)
}
/**
* @dev Sets the "Precrime" address, which could be an address for handling fraudulent activities or other specific
* behaviors.
*
* Requirements:
* - Only the owner can set the Precrime address.
*
* @param _precrime The address to be set as Precrime.
*/
function setPrecrime(address _precrime) external onlyOwner {
LzAppStorage storage $ = _getLzAppStorage();
$.precrime = _precrime;
emit SetPrecrime(_precrime);
}
/**
* @dev Sets the minimum required gas for a specific packet type and destination chain.
*
* Requirements:
* - Only the owner can set the minimum destination gas.
*
* @param dstChainId The ID of the destination chain for which the minimum gas is being set.
* @param packetType The type of the packet for which the minimum gas is being set.
* @param minGas The minimum required gas in units.
*/
function setMinDstGas(uint16 dstChainId, uint16 packetType, uint256 minGas) external onlyOwner {
LzAppStorage storage $ = _getLzAppStorage();
$.minDstGasLookup[dstChainId][packetType] = minGas;
emit SetMinDstGas(dstChainId, packetType, minGas);
}
/**
* @dev Sets the payload size limit for a specific destination chain.
*
* Requirements:
* - Only the owner can set the payload size limit.
*
* @param dstChainId The ID of the destination chain for which the payload size limit is being set.
* @param size The size limit in bytes.
*/
function setPayloadSizeLimit(uint16 dstChainId, uint256 size) external onlyOwner {
LzAppStorage storage $ = _getLzAppStorage();
$.payloadSizeLimitLookup[dstChainId] = size;
}
/**
* @dev Checks whether a given source chain and address are trusted for receiving LayerZero messages.
*
* @param srcChainId The ID of the source chain to be checked.
* @param srcAddress The address on the source chain to be verified.
* @return A boolean indicating whether the source chain and address are trusted.
*/
function isTrustedRemote(uint16 srcChainId, bytes calldata srcAddress) external view returns (bool) {
LzAppStorage storage $ = _getLzAppStorage();
bytes memory trustedSource = $.trustedRemoteLookup[srcChainId];
return keccak256(trustedSource) == keccak256(srcAddress);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
*
* The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
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: MIT
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.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 lzApp 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);
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@layerzerolabs/contracts/=lib/endpoint-v1-solidity-examples/contracts/",
"endpoint-v1-solidity-examples/=lib/endpoint-v1-solidity-examples/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"lzEndpoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"CantRenounceOwnership","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SupplyLimitExceeded","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"ZeroAddressException","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"MessageFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMinter","type":"address"},{"indexed":true,"internalType":"address","name":"oldMinter","type":"address"}],"name":"MinterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"ReceiveFromChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"RetryMessageSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_toAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"SendToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_type","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_path","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_useCustomAdapterParams","type":"bool"}],"name":"SetUseCustomAdapterParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStakedmsUSD","type":"address"},{"indexed":true,"internalType":"address","name":"oldStakedmsUSD","type":"address"}],"name":"StakedmsUSDUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newSupplyLimit","type":"uint256"}],"name":"SupplyLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_PAYLOAD_SIZE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_EXTRA_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_SEND","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"circulatingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"bytes","name":"toAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"useZro","type":"bool"},{"internalType":"bytes","name":"adapterParams","type":"bytes"}],"name":"estimateSendFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"failedMessages","outputs":[{"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId","type":"uint16"}],"name":"getTrustedRemoteAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint16","name":"packetType","type":"uint16"}],"name":"minDstGasLookup","outputs":[{"internalType":"uint256","name":"minGas","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"nonblockingLzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId","type":"uint16"}],"name":"payloadSizeLimitLookup","outputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"_precrime","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"retryMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"bytes","name":"_toAddress","type":"bytes"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"address","name":"_zroPaymentAddress","type":"address"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"sendFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint256","name":"configType","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint16","name":"packetType","type":"uint16"},{"internalType":"uint256","name":"minGas","type":"uint256"}],"name":"setMinDstGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMinter","type":"address"}],"name":"setMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"setPayloadSizeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_precrime","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStakedmsUSD","type":"address"}],"name":"setStakedmsUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setSupplyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId","type":"uint16"},{"internalType":"bytes","name":"path","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId","type":"uint16"},{"internalType":"bytes","name":"remoteAddress","type":"bytes"}],"name":"setTrustedRemoteAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"useCustomAdapterParams","type":"bool"}],"name":"setUseCustomAdapterParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedmsUSD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supplyLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"path","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60c06040523060805234801562000014575f80fd5b50604051620040cf380380620040cf833981016040819052620000379162000109565b6001600160a01b03811660a0526200004e62000055565b5062000138565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000a65760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620001065780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b5f602082840312156200011a575f80fd5b81516001600160a01b038116811462000131575f80fd5b9392505050565b60805160a051613f2f620001a05f395f818161093201528181610ad501528181610e1c01528181610ef501528181610f92015281816111ae0152818161196901528181611df60152612a4201525f81816121240152818161214d015261232d0152613f2f5ff3fe608060405260043610610340575f3560e01c8063715018a6116101bd578063b353aaa7116100f2578063df2a5b3b11610092578063f2fde38b1161006d578063f2fde38b14610a55578063f5ecbdbc14610a74578063fc0c546a14610a93578063fca3b5aa14610aa5575f80fd5b8063df2a5b3b146109f8578063eab45d9c14610a17578063eb8d72b714610a36575f80fd5b8063c4461834116100cd578063c446183414610992578063cbed8b9c146109a7578063d1deba1f146109c6578063dd62ed3e146109d9575f80fd5b8063b353aaa714610921578063baf3292d14610954578063be90dac514610973575f80fd5b80639358928b1161015d5780639f38369a116101385780639f38369a14610894578063a6c3d165146108b3578063a9059cbb146108d2578063ad3cb1cc146108f1575f80fd5b80639358928b14610830578063950c8a741461084457806395d89b4114610880575f80fd5b80638732b2b2116101985780638732b2b2146107585780638cfd8f5c146107775780638da5cb5b146107d55780639065714714610811575f80fd5b8063715018a6146107065780637533d7881461071a57806379cc679014610739575f80fd5b8063361fab25116102935780634c42899a1161023357806352d1902d1161020e57806352d1902d146106745780635b8c41e61461068857806366ad5c8a146106a757806370a08231146106c6575f80fd5b80634c42899a146106285780634f1ef2861461064e5780635190563614610661575f80fd5b806340c10f191161026e57806340c10f19146105b857806342966c68146105d757806342d65a8d146105f65780634477051514610615575f80fd5b8063361fab251461052c5780633d8b38f61461054b5780633f1f4fa41461056a575f80fd5b80630df37483116102fe57806319d1997a116102d957806319d1997a146104aa57806323b872dd146104be5780632a205e3d146104dd578063313ce56714610511575f80fd5b80630df374831461042f57806310ddb1371461044e57806318160ddd1461046d575f80fd5b80621d35671461034457806301ffc9a71461036557806306fdde031461039957806307546172146103ba57806307e0db17146103f1578063095ea7b314610410575b5f80fd5b34801561034f575f80fd5b5061036361035e3660046131c1565b610ac4565b005b348015610370575f80fd5b5061038461037f366004613250565b610cfe565b60405190151581526020015b60405180910390f35b3480156103a4575f80fd5b506103ad610d3b565b60405161039091906132c4565b3480156103c5575f80fd5b506001546103d9906001600160a01b031681565b6040516001600160a01b039091168152602001610390565b3480156103fc575f80fd5b5061036361040b3660046132d6565b610dfb565b34801561041b575f80fd5b5061038461042a366004613305565b610e7f565b34801561043a575f80fd5b5061036361044936600461332f565b610e96565b348015610459575f80fd5b506103636104683660046132d6565b610ed4565b348015610478575f80fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610390565b3480156104b5575f80fd5b5061049c5f5481565b3480156104c9575f80fd5b506103846104d836600461334b565b610f2c565b3480156104e8575f80fd5b506104fc6104f7366004613398565b610f51565b60408051928352602083019190915201610390565b34801561051c575f80fd5b5060405160128152602001610390565b348015610537575f80fd5b50610363610546366004613430565b611020565b348015610556575f80fd5b50610384610565366004613447565b611056565b348015610575575f80fd5b5061049c6105843660046132d6565b61ffff165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b02602052604090205490565b3480156105c3575f80fd5b506103636105d2366004613305565b61112e565b3480156105e2575f80fd5b506103636105f1366004613430565b611182565b348015610601575f80fd5b50610363610610366004613447565b61118f565b348015610620575f80fd5b5061049c5f81565b348015610633575f80fd5b5061063b5f81565b60405161ffff9091168152602001610390565b61036361065c36600461353c565b611219565b61036361066f36600461359b565b611234565b34801561067f575f80fd5b5061049c6112b7565b348015610693575f80fd5b5061049c6106a236600461365c565b6112d2565b3480156106b2575f80fd5b506103636106c13660046131c1565b611346565b3480156106d1575f80fd5b5061049c6106e03660046136be565b6001600160a01b03165f9081525f80516020613ec3833981519152602052604090205490565b348015610711575f80fd5b50610363611420565b348015610725575f80fd5b506103ad6107343660046132d6565b611441565b348015610744575f80fd5b50610363610753366004613305565b6114f6565b348015610763575f80fd5b506103636107723660046136be565b61151b565b348015610782575f80fd5b5061049c6107913660046136d9565b61ffff9182165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b016020908152604080832093909416825291909152205490565b3480156107e0575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166103d9565b34801561081c575f80fd5b5061036361082b36600461372e565b61157e565b34801561083b575f80fd5b5061049c61168d565b34801561084f575f80fd5b507f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b03546001600160a01b03166103d9565b34801561088b575f80fd5b506103ad6116bb565b34801561089f575f80fd5b506103ad6108ae3660046132d6565b6116f9565b3480156108be575f80fd5b506103636108cd366004613447565b611819565b3480156108dd575f80fd5b506103846108ec366004613305565b6118b1565b3480156108fc575f80fd5b506103ad604051806040016040528060058152602001640352e302e360dc1b81525081565b34801561092c575f80fd5b506103d97f000000000000000000000000000000000000000000000000000000000000000081565b34801561095f575f80fd5b5061036361096e3660046136be565b6118be565b34801561097e575f80fd5b506002546103d9906001600160a01b031681565b34801561099d575f80fd5b5061049c61271081565b3480156109b2575f80fd5b506103636109c136600461379e565b61194a565b6103636109d43660046131c1565b6119cf565b3480156109e4575f80fd5b5061049c6109f336600461380b565b611bdc565b348015610a03575f80fd5b50610363610a12366004613837565b611c25565b348015610a22575f80fd5b50610363610a31366004613864565b611cbc565b348015610a41575f80fd5b50610363610a50366004613447565b611d23565b348015610a60575f80fd5b50610363610a6f3660046136be565b611d8b565b348015610a7f575f80fd5b506103ad610a8e36600461387d565b611dc5565b348015610a9e575f80fd5b50306103d9565b348015610ab0575f80fd5b50610363610abf3660046136be565b611e72565b5f80516020613f03833981519152337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614610b4f5760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff87165f9081526020829052604081208054610b6c906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054610b98906138cb565b8015610be35780601f10610bba57610100808354040283529160200191610be3565b820191905f5260205f20905b815481529060010190602001808311610bc657829003601f168201915b50505050509050805187879050148015610bfd5750805115155b8015610c25575080516020820120604051610c1b9089908990613903565b6040518091039020145b610c805760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b6064820152608401610b46565b610cf48888888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8b018190048102820181019092528981528b9350915089908990819084018382808284375f92019190915250611ed692505050565b5050505050505050565b5f6001600160e01b031982161580610d2657506001600160e01b031982166336372b0760e01b145b80610d355750610d3582611f4e565b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060915f80516020613ec383398151915291610d79906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054610da5906138cb565b8015610df05780601f10610dc757610100808354040283529160200191610df0565b820191905f5260205f20905b815481529060010190602001808311610dd357829003601f168201915b505050505091505090565b610e03611f82565b6040516307e0db1760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906307e0db17906024015b5f604051808303815f87803b158015610e66575f80fd5b505af1158015610e78573d5f803e3d5ffd5b5050505050565b5f33610e8c818585611fdf565b5060019392505050565b610e9e611f82565b61ffff919091165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b026020526040902055565b610edc611f82565b6040516310ddb13760e01b815261ffff821660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906310ddb13790602401610e4f565b5f33610f39858285611ff1565b610f44858585612054565b60019150505b9392505050565b5f805f80898989604051602001610f6b949392919061393a565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340a7bb1090610fd1908d90309086908c908c908c90600401613968565b6040805180830381865afa158015610feb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061100f91906139bd565b925092505097509795505050505050565b611028611f82565b60405181907f83bf0eae6b24a5118d0e1785ec3cb5339523158ea9543256a8de3443a74b2e4a905f90a25f55565b61ffff83165f9081525f80516020613f038339815191526020819052604082208054839190611084906138cb565b80601f01602080910402602001604051908101604052809291908181526020018280546110b0906138cb565b80156110fb5780601f106110d2576101008083540402835291602001916110fb565b820191905f5260205f20905b8154815290600101906020018083116110de57829003601f168201915b505050505090508484604051611112929190613903565b6040518091039020818051906020012014925050509392505050565b6001546001600160a01b0316331480159061115457506002546001600160a01b03163314155b1561117457604051634a0bfec160e01b8152336004820152602401610b46565b61117e82826120b1565b5050565b61118c33826120e5565b50565b611197611f82565b6040516342d65a8d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906342d65a8d906111e7908690869086906004016139df565b5f604051808303815f87803b1580156111fe575f80fd5b505af1158015611210573d5f803e3d5ffd5b50505050505050565b611221612119565b61122a826121bd565b61117e82826121c5565b6112ac898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528c93508b92508a918a908a90819084018382808284375f9201919091525061228192505050565b505050505050505050565b5f6112c0612322565b505f80516020613ee383398151915290565b61ffff84165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d86006020819052604080832090516113159087908790613903565b908152604080519182900360209081019092206001600160401b0386165f9081529252902054915050949350505050565b3330146113a45760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b6064820152608401610b46565b6114188686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8901819004810282018101909252878152899350915087908790819084018382808284375f9201919091525061236b92505050565b505050505050565b611428611f82565b60405163185b73b160e01b815260040160405180910390fd5b61ffff81165f9081525f80516020613f038339815191526020819052604090912080546060929190611472906138cb565b80601f016020809104026020016040519081016040528092919081815260200182805461149e906138cb565b80156114e95780601f106114c0576101008083540402835291602001916114e9565b820191905f5260205f20905b8154815290600101906020018083116114cc57829003601f168201915b5050505050915050919050565b6001600160a01b038216331461151157611511823383611ff1565b61117e82826120e5565b611523611f82565b6002546040516001600160a01b03918216918316907e75f809b78c4f6fadba0022601a53ce89ce5515e726df1d2f37b993b0c765bd905f90a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f811580156115c25750825b90505f826001600160401b031660011480156115dd5750303b155b9050811580156115eb575080155b156116095760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561163357845460ff60401b1916600160401b1785555b61163e8888886123d2565b8315610cf457845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050505050565b5f6116b67f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b905090565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f80516020613ec383398151915291610d79906138cb565b61ffff81165f9081525f80516020613f0383398151915260208190526040822080546060939190611729906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054611755906138cb565b80156117a05780601f10611777576101008083540402835291602001916117a0565b820191905f5260205f20905b81548152906001019060200180831161178357829003601f168201915b5050505050905080515f036117f75760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f72640000006044820152606401610b46565b6118115f601483516118099190613a10565b8391906123f5565b949350505050565b611821611f82565b6040515f80516020613f038339815191529061184590849084903090602001613a23565b60408051601f1981840301815291815261ffff86165f9081526020849052209061186f9082613a8e565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516118a3939291906139df565b60405180910390a150505050565b5f33610e8c818585612054565b6118c6611f82565b7f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b0380546001600160a01b0319166001600160a01b0383169081179091556040519081525f80516020613f03833981519152907f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906020015b60405180910390a15050565b611952611f82565b6040516332fb62e760e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbed8b9c906119a69088908890889088908890600401613b49565b5f604051808303815f87803b1580156119bd575f80fd5b505af11580156112ac573d5f803e3d5ffd5b61ffff86165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d8600602081905260408083209051919291611a159089908990613903565b90815260408051602092819003830190206001600160401b0388165f9081529281905291205490915080611a975760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b6064820152608401610b46565b808585604051611aa8929190613903565b604051809103902014611b075760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b6064820152608401610b46565b6001600160401b0386165f90815260208381526040808320929092558151601f8a01829004820281018201909252888252611b92918b918b908b90819084018382808284375f9201919091525050604080516020601f8c018190048102820181019092528a81528c935091508a908a90819084018382808284375f9201919091525061236b92505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58989898985604051611bc9959493929190613b81565b60405180910390a1505050505050505050565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b611c2d611f82565b61ffff8381165f8181527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b01602090815260408083209487168084529482529182902085905581519283528201929092529081018290525f80516020613f03833981519152907f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac0906060016118a3565b611cc4611f82565b7f822492242235517548c4a8cf040400e3c0daf5b82af652ed16dce4fa3ae72800805460ff191682151590811782556040519081527f1584ad594a70cbe1e6515592e1272a987d922b097ead875069cebe8b40c004a49060200161193e565b611d2b611f82565b61ffff83165f9081525f80516020613f0383398151915260208190526040909120611d57838583613bbb565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516118a3939291906139df565b611d93611f82565b6001600160a01b038116611dbc57604051631e4fbdf760e01b81525f6004820152602401610b46565b61118c81612501565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f5ecbdbc906084015f60405180830381865afa158015611e42573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e699190810190613cb7565b95945050505050565b611e7a611f82565b6001546040516001600160a01b03918216918316907f1cf2de25c5bf439ac0287061c3a0fa69b3b02867d0ccfd2ded34e42577050b73905f90a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b5f80611f385a60966366ad5c8a60e01b89898989604051602401611efd9493929190613ce8565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915230929190612571565b91509150816114185761141886868686856125f5565b5f6001600160e01b03198216630a72677560e11b1480610d3557506301ffc9a760e01b6001600160e01b0319831614610d35565b33611fb47f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611fdd5760405163118cdaa760e01b8152336004820152602401610b46565b565b611fec83838360016126ad565b505050565b5f611ffc8484611bdc565b90505f19811461204e578181101561204057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610b46565b61204e84848484035f6126ad565b50505050565b6001600160a01b03831661207d57604051634b637e8f60e11b81525f6004820152602401610b46565b6001600160a01b0382166120a65760405163ec442f0560e01b81525f6004820152602401610b46565b611fec838383612790565b6001600160a01b0382166120da5760405163ec442f0560e01b81525f6004820152602401610b46565b61117e5f8383612790565b6001600160a01b03821661210e57604051634b637e8f60e11b81525f6004820152602401610b46565b61117e825f83612790565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061219f57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166121935f80516020613ee3833981519152546001600160a01b031690565b6001600160a01b031614155b15611fdd5760405163703e46dd60e11b815260040160405180910390fd5b61118c611f82565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561221f575060408051601f3d908101601f1916820190925261221c91810190613d25565b60015b61224757604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610b46565b5f80516020613ee3833981519152811461227757604051632a87526960e21b815260048101829052602401610b46565b611fec83836127f1565b61228d865f835f612846565b612299878787876128db565b93505f8086866040516020016122b193929190613d3c565b60405160208183030381529060405290506122d087828686863461290c565b876001600160a01b03168761ffff167f39a4c66499bcf4b56d79f0dde8ed7a9d4925a0df55825206b2b8531e202be0d08888604051612310929190613d68565b60405180910390a35050505050505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611fdd5760405163703e46dd60e11b815260040160405180910390fd5b602081015161ffff811661238a5761238585858585612abb565b610e78565b60405162461bcd60e51b815260206004820152601c60248201527f4f4654436f72653a20756e6b6e6f776e207061636b65742074797065000000006044820152606401610b46565b6123da612b43565b6123e2612b8c565b6123eb83612b94565b611fec8282612bad565b60608161240381601f613d89565b10156124425760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610b46565b61244c8284613d89565b845110156124905760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610b46565b6060821580156124ae5760405191505f8252602082016040526124f8565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124e75780518352602092830192016124cf565b5050858452601f01601f1916604052505b50949350505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f60605f805f8661ffff166001600160401b0381111561259357612593613497565b6040519080825280601f01601f1916602001820160405280156125bd576020820181803683370190505b5090505f808751602089015f8d8df191503d9250868311156125dd578692505b828152825f602083013e909890975095505050505050565b815160208084019190912061ffff87165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d8600928390526040908190209051612641908890613d9c565b9081526040805191829003602090810183206001600160401b0389165f908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c9061269d9088908890889088908890613db7565b60405180910390a1505050505050565b5f80516020613ec38339815191526001600160a01b0385166126e45760405163e602df0560e01b81525f6004820152602401610b46565b6001600160a01b03841661270d57604051634a1406b160e11b81525f6004820152602401610b46565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610e7857836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161278191815260200190565b60405180910390a35050505050565b61279b838383612bbf565b6001600160a01b0383161580156127d357505f547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254115b15611fec576040516327f34da760e11b815260040160405180910390fd5b6127fa82612cf8565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561283e57611fec8282612d5b565b61117e612dc4565b7f822492242235517548c4a8cf040400e3c0daf5b82af652ed16dce4fa3ae72800805460ff161561287d5761238585858585612de3565b825115610e785760405162461bcd60e51b815260206004820152602660248201527f4f4654436f72653a205f61646170746572506172616d73206d7573742062652060448201526532b6b83a3c9760d11b6064820152608401610b46565b5f336001600160a01b03861681146128f8576128f8868285611ff1565b61290286846120e5565b5090949350505050565b61ffff86165f9081525f80516020613f03833981519152602081905260408220805491929161293a906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054612966906138cb565b80156129b15780601f10612988576101008083540402835291602001916129b1565b820191905f5260205f20905b81548152906001019060200180831161299457829003601f168201915b5050505050905080515f03612a215760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b6064820152608401610b46565b612a2c888851612eca565b60405162c5803160e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c5803100908590612a83908c9086908d908d908d908d90600401613e14565b5f604051808303818588803b158015612a9a575f80fd5b505af1158015612aac573d5f803e3d5ffd5b50505050505050505050505050565b5f8082806020019051810190612ad19190613e6d565b90935091505f9050612ae38382612f67565b9050612af0878284612fcb565b9150806001600160a01b03168761ffff167fbf551ec93859b170f9b2141bd9298bf3f64322c6f7beb2543a0cb669834118bf84604051612b3291815260200190565b60405180910390a350505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16611fdd57604051631afcd79f60e31b815260040160405180910390fd5b611fdd612b43565b612b9c612b43565b612ba4612b8c565b61118c81612fdd565b612bb5612b43565b61117e8282612ff6565b5f80516020613ec38339815191526001600160a01b038416612bf95781816002015f828254612bee9190613d89565b90915550612c699050565b6001600160a01b0384165f9081526020829052604090205482811015612c4b5760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610b46565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316612c87576002810180548390039055612ca5565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051612cea91815260200190565b60405180910390a350505050565b806001600160a01b03163b5f03612d2d57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610b46565b5f80516020613ee383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b031684604051612d779190613d9c565b5f60405180830381855af49150503d805f8114612daf576040519150601f19603f3d011682016040523d82523d5f602084013e612db4565b606091505b5091509150611e69858383613046565b3415611fdd5760405163b398979f60e01b815260040160405180910390fd5b5f80516020613f038339815191525f612dfb846130a2565b61ffff8088165f9081526001850160209081526040808320938a16835292905290812054919250819003612e715760405162461bcd60e51b815260206004820152601a60248201527f4c7a4170703a206d696e4761734c696d6974206e6f74207365740000000000006044820152606401610b46565b612e7b8482613d89565b8210156112105760405162461bcd60e51b815260206004820152601b60248201527f4c7a4170703a20676173206c696d697420697320746f6f206c6f7700000000006044820152606401610b46565b61ffff82165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b0260205260408120545f80516020613f0383398151915291819003612f1757506127105b8083111561204e5760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c617267656044820152606401610b46565b5f612f73826014613d89565b83511015612fbb5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610b46565b500160200151600160601b900490565b5f612fd683836120b1565b5092915050565b612fe5612b43565b612fed612b8c565b61118c816130fd565b612ffe612b43565b5f80516020613ec38339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036130378482613a8e565b506004810161204e8382613a8e565b60608261305b5761305682613116565b610f4a565b815115801561307257506001600160a01b0384163b155b1561309b57604051639996b31560e01b81526001600160a01b0385166004820152602401610b46565b5080610f4a565b5f6022825110156130f55760405162461bcd60e51b815260206004820152601c60248201527f4c7a4170703a20696e76616c69642061646170746572506172616d73000000006044820152606401610b46565b506022015190565b613105612b43565b61310d612b8c565b61118c8161313f565b8051156131265780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b613147612b43565b61118c81611d93612b43565b61ffff8116811461118c575f80fd5b5f8083601f840112613172575f80fd5b5081356001600160401b03811115613188575f80fd5b60208301915083602082850101111561319f575f80fd5b9250929050565b80356001600160401b03811681146131bc575f80fd5b919050565b5f805f805f80608087890312156131d6575f80fd5b86356131e181613153565b955060208701356001600160401b03808211156131fc575f80fd5b6132088a838b01613162565b909750955085915061321c60408a016131a6565b94506060890135915080821115613231575f80fd5b5061323e89828a01613162565b979a9699509497509295939492505050565b5f60208284031215613260575f80fd5b81356001600160e01b031981168114610f4a575f80fd5b5f5b83811015613291578181015183820152602001613279565b50505f910152565b5f81518084526132b0816020860160208601613277565b601f01601f19169290920160200192915050565b602081525f610f4a6020830184613299565b5f602082840312156132e6575f80fd5b8135610f4a81613153565b6001600160a01b038116811461118c575f80fd5b5f8060408385031215613316575f80fd5b8235613321816132f1565b946020939093013593505050565b5f8060408385031215613340575f80fd5b823561332181613153565b5f805f6060848603121561335d575f80fd5b8335613368816132f1565b92506020840135613378816132f1565b929592945050506040919091013590565b803580151581146131bc575f80fd5b5f805f805f805f60a0888a0312156133ae575f80fd5b87356133b981613153565b965060208801356001600160401b03808211156133d4575f80fd5b6133e08b838c01613162565b909850965060408a013595508691506133fb60608b01613389565b945060808a0135915080821115613410575f80fd5b5061341d8a828b01613162565b989b979a50959850939692959293505050565b5f60208284031215613440575f80fd5b5035919050565b5f805f60408486031215613459575f80fd5b833561346481613153565b925060208401356001600160401b0381111561347e575f80fd5b61348a86828701613162565b9497909650939450505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156134d3576134d3613497565b604052919050565b5f6001600160401b038211156134f3576134f3613497565b50601f01601f191660200190565b5f61351361350e846134db565b6134ab565b9050828152838383011115613526575f80fd5b828260208301375f602084830101529392505050565b5f806040838503121561354d575f80fd5b8235613558816132f1565b915060208301356001600160401b03811115613572575f80fd5b8301601f81018513613582575f80fd5b61359185823560208401613501565b9150509250929050565b5f805f805f805f805f60e08a8c0312156135b3575f80fd5b89356135be816132f1565b985060208a01356135ce81613153565b975060408a01356001600160401b03808211156135e9575f80fd5b6135f58d838e01613162565b909950975060608c0135965060808c01359150613611826132f1565b90945060a08b013590613623826132f1565b90935060c08b01359080821115613638575f80fd5b506136458c828d01613162565b915080935050809150509295985092959850929598565b5f805f806060858703121561366f575f80fd5b843561367a81613153565b935060208501356001600160401b03811115613694575f80fd5b6136a087828801613162565b90945092506136b39050604086016131a6565b905092959194509250565b5f602082840312156136ce575f80fd5b8135610f4a816132f1565b5f80604083850312156136ea575f80fd5b82356136f581613153565b9150602083013561370581613153565b809150509250929050565b5f82601f83011261371f575f80fd5b610f4a83833560208501613501565b5f805f60608486031215613740575f80fd5b833561374b816132f1565b925060208401356001600160401b0380821115613766575f80fd5b61377287838801613710565b93506040860135915080821115613787575f80fd5b5061379486828701613710565b9150509250925092565b5f805f805f608086880312156137b2575f80fd5b85356137bd81613153565b945060208601356137cd81613153565b93506040860135925060608601356001600160401b038111156137ee575f80fd5b6137fa88828901613162565b969995985093965092949392505050565b5f806040838503121561381c575f80fd5b8235613827816132f1565b91506020830135613705816132f1565b5f805f60608486031215613849575f80fd5b833561385481613153565b9250602084013561337881613153565b5f60208284031215613874575f80fd5b610f4a82613389565b5f805f8060808587031215613890575f80fd5b843561389b81613153565b935060208501356138ab81613153565b925060408501356138bb816132f1565b9396929550929360600135925050565b600181811c908216806138df57607f821691505b6020821081036138fd57634e487b7160e01b5f52602260045260245ffd5b50919050565b818382375f9101908152919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61ffff85168152606060208201525f613957606083018587613912565b905082604083015295945050505050565b61ffff871681526001600160a01b038616602082015260a0604082018190525f9061399590830187613299565b851515606084015282810360808401526139b0818587613912565b9998505050505050505050565b5f80604083850312156139ce575f80fd5b505080516020909101519092909150565b61ffff84168152604060208201525f611e69604083018486613912565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d3557610d356139fc565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b601f821115611fec575f81815260208120601f850160051c81016020861015613a6f5750805b601f850160051c820191505b8181101561141857828155600101613a7b565b81516001600160401b03811115613aa757613aa7613497565b613abb81613ab584546138cb565b84613a49565b602080601f831160018114613aee575f8415613ad75750858301515b5f19600386901b1c1916600185901b178555611418565b5f85815260208120601f198616915b82811015613b1c57888601518255948401946001909101908401613afd565b5085821015613b3957878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61ffff808816835280871660208401525084604083015260806060830152613b76608083018486613912565b979650505050505050565b61ffff86168152608060208201525f613b9e608083018688613912565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b03831115613bd257613bd2613497565b613be683613be083546138cb565b83613a49565b5f601f841160018114613c17575f8515613c005750838201355b5f19600387901b1c1916600186901b178355610e78565b5f83815260209020601f19861690835b82811015613c475786850135825560209485019460019092019101613c27565b5086821015613c63575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f82601f830112613c84575f80fd5b8151613c9261350e826134db565b818152846020838601011115613ca6575f80fd5b611811826020830160208701613277565b5f60208284031215613cc7575f80fd5b81516001600160401b03811115613cdc575f80fd5b61181184828501613c75565b61ffff85168152608060208201525f613d046080830186613299565b6001600160401b03851660408401528281036060840152613b768185613299565b5f60208284031215613d35575f80fd5b5051919050565b61ffff84168152606060208201525f613d586060830185613299565b9050826040830152949350505050565b604081525f613d7a6040830185613299565b90508260208301529392505050565b80820180821115610d3557610d356139fc565b5f8251613dad818460208701613277565b9190910192915050565b61ffff8616815260a060208201525f613dd360a0830187613299565b6001600160401b03861660408401528281036060840152613df48186613299565b90508281036080840152613e088185613299565b98975050505050505050565b61ffff8716815260c060208201525f613e3060c0830188613299565b8281036040840152613e428188613299565b6001600160a01b0387811660608601528616608085015283810360a085015290506139b08185613299565b5f805f60608486031215613e7f575f80fd5b8351613e8a81613153565b60208501519093506001600160401b03811115613ea5575f80fd5b613eb186828701613c75565b92505060408401519050925092509256fe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b00a164736f6c6343000814000a000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7
Deployed Bytecode
0x608060405260043610610340575f3560e01c8063715018a6116101bd578063b353aaa7116100f2578063df2a5b3b11610092578063f2fde38b1161006d578063f2fde38b14610a55578063f5ecbdbc14610a74578063fc0c546a14610a93578063fca3b5aa14610aa5575f80fd5b8063df2a5b3b146109f8578063eab45d9c14610a17578063eb8d72b714610a36575f80fd5b8063c4461834116100cd578063c446183414610992578063cbed8b9c146109a7578063d1deba1f146109c6578063dd62ed3e146109d9575f80fd5b8063b353aaa714610921578063baf3292d14610954578063be90dac514610973575f80fd5b80639358928b1161015d5780639f38369a116101385780639f38369a14610894578063a6c3d165146108b3578063a9059cbb146108d2578063ad3cb1cc146108f1575f80fd5b80639358928b14610830578063950c8a741461084457806395d89b4114610880575f80fd5b80638732b2b2116101985780638732b2b2146107585780638cfd8f5c146107775780638da5cb5b146107d55780639065714714610811575f80fd5b8063715018a6146107065780637533d7881461071a57806379cc679014610739575f80fd5b8063361fab25116102935780634c42899a1161023357806352d1902d1161020e57806352d1902d146106745780635b8c41e61461068857806366ad5c8a146106a757806370a08231146106c6575f80fd5b80634c42899a146106285780634f1ef2861461064e5780635190563614610661575f80fd5b806340c10f191161026e57806340c10f19146105b857806342966c68146105d757806342d65a8d146105f65780634477051514610615575f80fd5b8063361fab251461052c5780633d8b38f61461054b5780633f1f4fa41461056a575f80fd5b80630df37483116102fe57806319d1997a116102d957806319d1997a146104aa57806323b872dd146104be5780632a205e3d146104dd578063313ce56714610511575f80fd5b80630df374831461042f57806310ddb1371461044e57806318160ddd1461046d575f80fd5b80621d35671461034457806301ffc9a71461036557806306fdde031461039957806307546172146103ba57806307e0db17146103f1578063095ea7b314610410575b5f80fd5b34801561034f575f80fd5b5061036361035e3660046131c1565b610ac4565b005b348015610370575f80fd5b5061038461037f366004613250565b610cfe565b60405190151581526020015b60405180910390f35b3480156103a4575f80fd5b506103ad610d3b565b60405161039091906132c4565b3480156103c5575f80fd5b506001546103d9906001600160a01b031681565b6040516001600160a01b039091168152602001610390565b3480156103fc575f80fd5b5061036361040b3660046132d6565b610dfb565b34801561041b575f80fd5b5061038461042a366004613305565b610e7f565b34801561043a575f80fd5b5061036361044936600461332f565b610e96565b348015610459575f80fd5b506103636104683660046132d6565b610ed4565b348015610478575f80fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610390565b3480156104b5575f80fd5b5061049c5f5481565b3480156104c9575f80fd5b506103846104d836600461334b565b610f2c565b3480156104e8575f80fd5b506104fc6104f7366004613398565b610f51565b60408051928352602083019190915201610390565b34801561051c575f80fd5b5060405160128152602001610390565b348015610537575f80fd5b50610363610546366004613430565b611020565b348015610556575f80fd5b50610384610565366004613447565b611056565b348015610575575f80fd5b5061049c6105843660046132d6565b61ffff165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b02602052604090205490565b3480156105c3575f80fd5b506103636105d2366004613305565b61112e565b3480156105e2575f80fd5b506103636105f1366004613430565b611182565b348015610601575f80fd5b50610363610610366004613447565b61118f565b348015610620575f80fd5b5061049c5f81565b348015610633575f80fd5b5061063b5f81565b60405161ffff9091168152602001610390565b61036361065c36600461353c565b611219565b61036361066f36600461359b565b611234565b34801561067f575f80fd5b5061049c6112b7565b348015610693575f80fd5b5061049c6106a236600461365c565b6112d2565b3480156106b2575f80fd5b506103636106c13660046131c1565b611346565b3480156106d1575f80fd5b5061049c6106e03660046136be565b6001600160a01b03165f9081525f80516020613ec3833981519152602052604090205490565b348015610711575f80fd5b50610363611420565b348015610725575f80fd5b506103ad6107343660046132d6565b611441565b348015610744575f80fd5b50610363610753366004613305565b6114f6565b348015610763575f80fd5b506103636107723660046136be565b61151b565b348015610782575f80fd5b5061049c6107913660046136d9565b61ffff9182165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b016020908152604080832093909416825291909152205490565b3480156107e0575f80fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166103d9565b34801561081c575f80fd5b5061036361082b36600461372e565b61157e565b34801561083b575f80fd5b5061049c61168d565b34801561084f575f80fd5b507f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b03546001600160a01b03166103d9565b34801561088b575f80fd5b506103ad6116bb565b34801561089f575f80fd5b506103ad6108ae3660046132d6565b6116f9565b3480156108be575f80fd5b506103636108cd366004613447565b611819565b3480156108dd575f80fd5b506103846108ec366004613305565b6118b1565b3480156108fc575f80fd5b506103ad604051806040016040528060058152602001640352e302e360dc1b81525081565b34801561092c575f80fd5b506103d97f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd781565b34801561095f575f80fd5b5061036361096e3660046136be565b6118be565b34801561097e575f80fd5b506002546103d9906001600160a01b031681565b34801561099d575f80fd5b5061049c61271081565b3480156109b2575f80fd5b506103636109c136600461379e565b61194a565b6103636109d43660046131c1565b6119cf565b3480156109e4575f80fd5b5061049c6109f336600461380b565b611bdc565b348015610a03575f80fd5b50610363610a12366004613837565b611c25565b348015610a22575f80fd5b50610363610a31366004613864565b611cbc565b348015610a41575f80fd5b50610363610a50366004613447565b611d23565b348015610a60575f80fd5b50610363610a6f3660046136be565b611d8b565b348015610a7f575f80fd5b506103ad610a8e36600461387d565b611dc5565b348015610a9e575f80fd5b50306103d9565b348015610ab0575f80fd5b50610363610abf3660046136be565b611e72565b5f80516020613f03833981519152337f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b031614610b4f5760405162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c6572000060448201526064015b60405180910390fd5b61ffff87165f9081526020829052604081208054610b6c906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054610b98906138cb565b8015610be35780601f10610bba57610100808354040283529160200191610be3565b820191905f5260205f20905b815481529060010190602001808311610bc657829003601f168201915b50505050509050805187879050148015610bfd5750805115155b8015610c25575080516020820120604051610c1b9089908990613903565b6040518091039020145b610c805760405162461bcd60e51b815260206004820152602660248201527f4c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6044820152651b9d1c9858dd60d21b6064820152608401610b46565b610cf48888888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8b018190048102820181019092528981528b9350915089908990819084018382808284375f92019190915250611ed692505050565b5050505050505050565b5f6001600160e01b031982161580610d2657506001600160e01b031982166336372b0760e01b145b80610d355750610d3582611f4e565b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0380546060915f80516020613ec383398151915291610d79906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054610da5906138cb565b8015610df05780601f10610dc757610100808354040283529160200191610df0565b820191905f5260205f20905b815481529060010190602001808311610dd357829003601f168201915b505050505091505090565b610e03611f82565b6040516307e0db1760e01b815261ffff821660048201527f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b0316906307e0db17906024015b5f604051808303815f87803b158015610e66575f80fd5b505af1158015610e78573d5f803e3d5ffd5b5050505050565b5f33610e8c818585611fdf565b5060019392505050565b610e9e611f82565b61ffff919091165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b026020526040902055565b610edc611f82565b6040516310ddb13760e01b815261ffff821660048201527f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b0316906310ddb13790602401610e4f565b5f33610f39858285611ff1565b610f44858585612054565b60019150505b9392505050565b5f805f80898989604051602001610f6b949392919061393a565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd716906340a7bb1090610fd1908d90309086908c908c908c90600401613968565b6040805180830381865afa158015610feb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061100f91906139bd565b925092505097509795505050505050565b611028611f82565b60405181907f83bf0eae6b24a5118d0e1785ec3cb5339523158ea9543256a8de3443a74b2e4a905f90a25f55565b61ffff83165f9081525f80516020613f038339815191526020819052604082208054839190611084906138cb565b80601f01602080910402602001604051908101604052809291908181526020018280546110b0906138cb565b80156110fb5780601f106110d2576101008083540402835291602001916110fb565b820191905f5260205f20905b8154815290600101906020018083116110de57829003601f168201915b505050505090508484604051611112929190613903565b6040518091039020818051906020012014925050509392505050565b6001546001600160a01b0316331480159061115457506002546001600160a01b03163314155b1561117457604051634a0bfec160e01b8152336004820152602401610b46565b61117e82826120b1565b5050565b61118c33826120e5565b50565b611197611f82565b6040516342d65a8d60e01b81526001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd716906342d65a8d906111e7908690869086906004016139df565b5f604051808303815f87803b1580156111fe575f80fd5b505af1158015611210573d5f803e3d5ffd5b50505050505050565b611221612119565b61122a826121bd565b61117e82826121c5565b6112ac898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8a018190048102820181019092528881528c93508b92508a918a908a90819084018382808284375f9201919091525061228192505050565b505050505050505050565b5f6112c0612322565b505f80516020613ee383398151915290565b61ffff84165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d86006020819052604080832090516113159087908790613903565b908152604080519182900360209081019092206001600160401b0386165f9081529252902054915050949350505050565b3330146113a45760405162461bcd60e51b815260206004820152602660248201527f4e6f6e626c6f636b696e674c7a4170703a2063616c6c6572206d7573742062656044820152650204c7a4170760d41b6064820152608401610b46565b6114188686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8901819004810282018101909252878152899350915087908790819084018382808284375f9201919091525061236b92505050565b505050505050565b611428611f82565b60405163185b73b160e01b815260040160405180910390fd5b61ffff81165f9081525f80516020613f038339815191526020819052604090912080546060929190611472906138cb565b80601f016020809104026020016040519081016040528092919081815260200182805461149e906138cb565b80156114e95780601f106114c0576101008083540402835291602001916114e9565b820191905f5260205f20905b8154815290600101906020018083116114cc57829003601f168201915b5050505050915050919050565b6001600160a01b038216331461151157611511823383611ff1565b61117e82826120e5565b611523611f82565b6002546040516001600160a01b03918216918316907e75f809b78c4f6fadba0022601a53ce89ce5515e726df1d2f37b993b0c765bd905f90a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f811580156115c25750825b90505f826001600160401b031660011480156115dd5750303b155b9050811580156115eb575080155b156116095760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561163357845460ff60401b1916600160401b1785555b61163e8888886123d2565b8315610cf457845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050505050565b5f6116b67f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace025490565b905090565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060915f80516020613ec383398151915291610d79906138cb565b61ffff81165f9081525f80516020613f0383398151915260208190526040822080546060939190611729906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054611755906138cb565b80156117a05780601f10611777576101008083540402835291602001916117a0565b820191905f5260205f20905b81548152906001019060200180831161178357829003601f168201915b5050505050905080515f036117f75760405162461bcd60e51b815260206004820152601d60248201527f4c7a4170703a206e6f20747275737465642070617468207265636f72640000006044820152606401610b46565b6118115f601483516118099190613a10565b8391906123f5565b949350505050565b611821611f82565b6040515f80516020613f038339815191529061184590849084903090602001613a23565b60408051601f1981840301815291815261ffff86165f9081526020849052209061186f9082613a8e565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516118a3939291906139df565b60405180910390a150505050565b5f33610e8c818585612054565b6118c6611f82565b7f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b0380546001600160a01b0319166001600160a01b0383169081179091556040519081525f80516020613f03833981519152907f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906020015b60405180910390a15050565b611952611f82565b6040516332fb62e760e21b81526001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7169063cbed8b9c906119a69088908890889088908890600401613b49565b5f604051808303815f87803b1580156119bd575f80fd5b505af11580156112ac573d5f803e3d5ffd5b61ffff86165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d8600602081905260408083209051919291611a159089908990613903565b90815260408051602092819003830190206001600160401b0388165f9081529281905291205490915080611a975760405162461bcd60e51b815260206004820152602360248201527f4e6f6e626c6f636b696e674c7a4170703a206e6f2073746f726564206d65737360448201526261676560e81b6064820152608401610b46565b808585604051611aa8929190613903565b604051809103902014611b075760405162461bcd60e51b815260206004820152602160248201527f4e6f6e626c6f636b696e674c7a4170703a20696e76616c6964207061796c6f616044820152601960fa1b6064820152608401610b46565b6001600160401b0386165f90815260208381526040808320929092558151601f8a01829004820281018201909252888252611b92918b918b908b90819084018382808284375f9201919091525050604080516020601f8c018190048102820181019092528a81528c935091508a908a90819084018382808284375f9201919091525061236b92505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e58989898985604051611bc9959493929190613b81565b60405180910390a1505050505050505050565b6001600160a01b039182165f9081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b611c2d611f82565b61ffff8381165f8181527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b01602090815260408083209487168084529482529182902085905581519283528201929092529081018290525f80516020613f03833981519152907f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac0906060016118a3565b611cc4611f82565b7f822492242235517548c4a8cf040400e3c0daf5b82af652ed16dce4fa3ae72800805460ff191682151590811782556040519081527f1584ad594a70cbe1e6515592e1272a987d922b097ead875069cebe8b40c004a49060200161193e565b611d2b611f82565b61ffff83165f9081525f80516020613f0383398151915260208190526040909120611d57838583613bbb565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516118a3939291906139df565b611d93611f82565b6001600160a01b038116611dbc57604051631e4fbdf760e01b81525f6004820152602401610b46565b61118c81612501565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b03169063f5ecbdbc906084015f60405180830381865afa158015611e42573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e699190810190613cb7565b95945050505050565b611e7a611f82565b6001546040516001600160a01b03918216918316907f1cf2de25c5bf439ac0287061c3a0fa69b3b02867d0ccfd2ded34e42577050b73905f90a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b5f80611f385a60966366ad5c8a60e01b89898989604051602401611efd9493929190613ce8565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915230929190612571565b91509150816114185761141886868686856125f5565b5f6001600160e01b03198216630a72677560e11b1480610d3557506301ffc9a760e01b6001600160e01b0319831614610d35565b33611fb47f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614611fdd5760405163118cdaa760e01b8152336004820152602401610b46565b565b611fec83838360016126ad565b505050565b5f611ffc8484611bdc565b90505f19811461204e578181101561204057604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610b46565b61204e84848484035f6126ad565b50505050565b6001600160a01b03831661207d57604051634b637e8f60e11b81525f6004820152602401610b46565b6001600160a01b0382166120a65760405163ec442f0560e01b81525f6004820152602401610b46565b611fec838383612790565b6001600160a01b0382166120da5760405163ec442f0560e01b81525f6004820152602401610b46565b61117e5f8383612790565b6001600160a01b03821661210e57604051634b637e8f60e11b81525f6004820152602401610b46565b61117e825f83612790565b306001600160a01b037f000000000000000000000000fbe86362f4fc7aac3acaf1b36ae211816f2fc47816148061219f57507f000000000000000000000000fbe86362f4fc7aac3acaf1b36ae211816f2fc4786001600160a01b03166121935f80516020613ee3833981519152546001600160a01b031690565b6001600160a01b031614155b15611fdd5760405163703e46dd60e11b815260040160405180910390fd5b61118c611f82565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561221f575060408051601f3d908101601f1916820190925261221c91810190613d25565b60015b61224757604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610b46565b5f80516020613ee3833981519152811461227757604051632a87526960e21b815260048101829052602401610b46565b611fec83836127f1565b61228d865f835f612846565b612299878787876128db565b93505f8086866040516020016122b193929190613d3c565b60405160208183030381529060405290506122d087828686863461290c565b876001600160a01b03168761ffff167f39a4c66499bcf4b56d79f0dde8ed7a9d4925a0df55825206b2b8531e202be0d08888604051612310929190613d68565b60405180910390a35050505050505050565b306001600160a01b037f000000000000000000000000fbe86362f4fc7aac3acaf1b36ae211816f2fc4781614611fdd5760405163703e46dd60e11b815260040160405180910390fd5b602081015161ffff811661238a5761238585858585612abb565b610e78565b60405162461bcd60e51b815260206004820152601c60248201527f4f4654436f72653a20756e6b6e6f776e207061636b65742074797065000000006044820152606401610b46565b6123da612b43565b6123e2612b8c565b6123eb83612b94565b611fec8282612bad565b60608161240381601f613d89565b10156124425760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610b46565b61244c8284613d89565b845110156124905760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610b46565b6060821580156124ae5760405191505f8252602082016040526124f8565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124e75780518352602092830192016124cf565b5050858452601f01601f1916604052505b50949350505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f60605f805f8661ffff166001600160401b0381111561259357612593613497565b6040519080825280601f01601f1916602001820160405280156125bd576020820181803683370190505b5090505f808751602089015f8d8df191503d9250868311156125dd578692505b828152825f602083013e909890975095505050505050565b815160208084019190912061ffff87165f9081527fe5a86fa43fa85f564c84895bd4f80ec5c29d03a57a0c1f7cb91d2cc05b4d8600928390526040908190209051612641908890613d9c565b9081526040805191829003602090810183206001600160401b0389165f908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c9061269d9088908890889088908890613db7565b60405180910390a1505050505050565b5f80516020613ec38339815191526001600160a01b0385166126e45760405163e602df0560e01b81525f6004820152602401610b46565b6001600160a01b03841661270d57604051634a1406b160e11b81525f6004820152602401610b46565b6001600160a01b038086165f90815260018301602090815260408083209388168352929052208390558115610e7857836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161278191815260200190565b60405180910390a35050505050565b61279b838383612bbf565b6001600160a01b0383161580156127d357505f547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0254115b15611fec576040516327f34da760e11b815260040160405180910390fd5b6127fa82612cf8565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561283e57611fec8282612d5b565b61117e612dc4565b7f822492242235517548c4a8cf040400e3c0daf5b82af652ed16dce4fa3ae72800805460ff161561287d5761238585858585612de3565b825115610e785760405162461bcd60e51b815260206004820152602660248201527f4f4654436f72653a205f61646170746572506172616d73206d7573742062652060448201526532b6b83a3c9760d11b6064820152608401610b46565b5f336001600160a01b03861681146128f8576128f8868285611ff1565b61290286846120e5565b5090949350505050565b61ffff86165f9081525f80516020613f03833981519152602081905260408220805491929161293a906138cb565b80601f0160208091040260200160405190810160405280929190818152602001828054612966906138cb565b80156129b15780601f10612988576101008083540402835291602001916129b1565b820191905f5260205f20905b81548152906001019060200180831161299457829003601f168201915b5050505050905080515f03612a215760405162461bcd60e51b815260206004820152603060248201527f4c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742060448201526f61207472757374656420736f7572636560801b6064820152608401610b46565b612a2c888851612eca565b60405162c5803160e81b81526001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7169063c5803100908590612a83908c9086908d908d908d908d90600401613e14565b5f604051808303818588803b158015612a9a575f80fd5b505af1158015612aac573d5f803e3d5ffd5b50505050505050505050505050565b5f8082806020019051810190612ad19190613e6d565b90935091505f9050612ae38382612f67565b9050612af0878284612fcb565b9150806001600160a01b03168761ffff167fbf551ec93859b170f9b2141bd9298bf3f64322c6f7beb2543a0cb669834118bf84604051612b3291815260200190565b60405180910390a350505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16611fdd57604051631afcd79f60e31b815260040160405180910390fd5b611fdd612b43565b612b9c612b43565b612ba4612b8c565b61118c81612fdd565b612bb5612b43565b61117e8282612ff6565b5f80516020613ec38339815191526001600160a01b038416612bf95781816002015f828254612bee9190613d89565b90915550612c699050565b6001600160a01b0384165f9081526020829052604090205482811015612c4b5760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610b46565b6001600160a01b0385165f9081526020839052604090209083900390555b6001600160a01b038316612c87576002810180548390039055612ca5565b6001600160a01b0383165f9081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051612cea91815260200190565b60405180910390a350505050565b806001600160a01b03163b5f03612d2d57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610b46565b5f80516020613ee383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b031684604051612d779190613d9c565b5f60405180830381855af49150503d805f8114612daf576040519150601f19603f3d011682016040523d82523d5f602084013e612db4565b606091505b5091509150611e69858383613046565b3415611fdd5760405163b398979f60e01b815260040160405180910390fd5b5f80516020613f038339815191525f612dfb846130a2565b61ffff8088165f9081526001850160209081526040808320938a16835292905290812054919250819003612e715760405162461bcd60e51b815260206004820152601a60248201527f4c7a4170703a206d696e4761734c696d6974206e6f74207365740000000000006044820152606401610b46565b612e7b8482613d89565b8210156112105760405162461bcd60e51b815260206004820152601b60248201527f4c7a4170703a20676173206c696d697420697320746f6f206c6f7700000000006044820152606401610b46565b61ffff82165f9081527f111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b0260205260408120545f80516020613f0383398151915291819003612f1757506127105b8083111561204e5760405162461bcd60e51b815260206004820181905260248201527f4c7a4170703a207061796c6f61642073697a6520697320746f6f206c617267656044820152606401610b46565b5f612f73826014613d89565b83511015612fbb5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b6044820152606401610b46565b500160200151600160601b900490565b5f612fd683836120b1565b5092915050565b612fe5612b43565b612fed612b8c565b61118c816130fd565b612ffe612b43565b5f80516020613ec38339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036130378482613a8e565b506004810161204e8382613a8e565b60608261305b5761305682613116565b610f4a565b815115801561307257506001600160a01b0384163b155b1561309b57604051639996b31560e01b81526001600160a01b0385166004820152602401610b46565b5080610f4a565b5f6022825110156130f55760405162461bcd60e51b815260206004820152601c60248201527f4c7a4170703a20696e76616c69642061646170746572506172616d73000000006044820152606401610b46565b506022015190565b613105612b43565b61310d612b8c565b61118c8161313f565b8051156131265780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b613147612b43565b61118c81611d93612b43565b61ffff8116811461118c575f80fd5b5f8083601f840112613172575f80fd5b5081356001600160401b03811115613188575f80fd5b60208301915083602082850101111561319f575f80fd5b9250929050565b80356001600160401b03811681146131bc575f80fd5b919050565b5f805f805f80608087890312156131d6575f80fd5b86356131e181613153565b955060208701356001600160401b03808211156131fc575f80fd5b6132088a838b01613162565b909750955085915061321c60408a016131a6565b94506060890135915080821115613231575f80fd5b5061323e89828a01613162565b979a9699509497509295939492505050565b5f60208284031215613260575f80fd5b81356001600160e01b031981168114610f4a575f80fd5b5f5b83811015613291578181015183820152602001613279565b50505f910152565b5f81518084526132b0816020860160208601613277565b601f01601f19169290920160200192915050565b602081525f610f4a6020830184613299565b5f602082840312156132e6575f80fd5b8135610f4a81613153565b6001600160a01b038116811461118c575f80fd5b5f8060408385031215613316575f80fd5b8235613321816132f1565b946020939093013593505050565b5f8060408385031215613340575f80fd5b823561332181613153565b5f805f6060848603121561335d575f80fd5b8335613368816132f1565b92506020840135613378816132f1565b929592945050506040919091013590565b803580151581146131bc575f80fd5b5f805f805f805f60a0888a0312156133ae575f80fd5b87356133b981613153565b965060208801356001600160401b03808211156133d4575f80fd5b6133e08b838c01613162565b909850965060408a013595508691506133fb60608b01613389565b945060808a0135915080821115613410575f80fd5b5061341d8a828b01613162565b989b979a50959850939692959293505050565b5f60208284031215613440575f80fd5b5035919050565b5f805f60408486031215613459575f80fd5b833561346481613153565b925060208401356001600160401b0381111561347e575f80fd5b61348a86828701613162565b9497909650939450505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156134d3576134d3613497565b604052919050565b5f6001600160401b038211156134f3576134f3613497565b50601f01601f191660200190565b5f61351361350e846134db565b6134ab565b9050828152838383011115613526575f80fd5b828260208301375f602084830101529392505050565b5f806040838503121561354d575f80fd5b8235613558816132f1565b915060208301356001600160401b03811115613572575f80fd5b8301601f81018513613582575f80fd5b61359185823560208401613501565b9150509250929050565b5f805f805f805f805f60e08a8c0312156135b3575f80fd5b89356135be816132f1565b985060208a01356135ce81613153565b975060408a01356001600160401b03808211156135e9575f80fd5b6135f58d838e01613162565b909950975060608c0135965060808c01359150613611826132f1565b90945060a08b013590613623826132f1565b90935060c08b01359080821115613638575f80fd5b506136458c828d01613162565b915080935050809150509295985092959850929598565b5f805f806060858703121561366f575f80fd5b843561367a81613153565b935060208501356001600160401b03811115613694575f80fd5b6136a087828801613162565b90945092506136b39050604086016131a6565b905092959194509250565b5f602082840312156136ce575f80fd5b8135610f4a816132f1565b5f80604083850312156136ea575f80fd5b82356136f581613153565b9150602083013561370581613153565b809150509250929050565b5f82601f83011261371f575f80fd5b610f4a83833560208501613501565b5f805f60608486031215613740575f80fd5b833561374b816132f1565b925060208401356001600160401b0380821115613766575f80fd5b61377287838801613710565b93506040860135915080821115613787575f80fd5b5061379486828701613710565b9150509250925092565b5f805f805f608086880312156137b2575f80fd5b85356137bd81613153565b945060208601356137cd81613153565b93506040860135925060608601356001600160401b038111156137ee575f80fd5b6137fa88828901613162565b969995985093965092949392505050565b5f806040838503121561381c575f80fd5b8235613827816132f1565b91506020830135613705816132f1565b5f805f60608486031215613849575f80fd5b833561385481613153565b9250602084013561337881613153565b5f60208284031215613874575f80fd5b610f4a82613389565b5f805f8060808587031215613890575f80fd5b843561389b81613153565b935060208501356138ab81613153565b925060408501356138bb816132f1565b9396929550929360600135925050565b600181811c908216806138df57607f821691505b6020821081036138fd57634e487b7160e01b5f52602260045260245ffd5b50919050565b818382375f9101908152919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61ffff85168152606060208201525f613957606083018587613912565b905082604083015295945050505050565b61ffff871681526001600160a01b038616602082015260a0604082018190525f9061399590830187613299565b851515606084015282810360808401526139b0818587613912565b9998505050505050505050565b5f80604083850312156139ce575f80fd5b505080516020909101519092909150565b61ffff84168152604060208201525f611e69604083018486613912565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610d3557610d356139fc565b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b601f821115611fec575f81815260208120601f850160051c81016020861015613a6f5750805b601f850160051c820191505b8181101561141857828155600101613a7b565b81516001600160401b03811115613aa757613aa7613497565b613abb81613ab584546138cb565b84613a49565b602080601f831160018114613aee575f8415613ad75750858301515b5f19600386901b1c1916600185901b178555611418565b5f85815260208120601f198616915b82811015613b1c57888601518255948401946001909101908401613afd565b5085821015613b3957878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f61ffff808816835280871660208401525084604083015260806060830152613b76608083018486613912565b979650505050505050565b61ffff86168152608060208201525f613b9e608083018688613912565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b03831115613bd257613bd2613497565b613be683613be083546138cb565b83613a49565b5f601f841160018114613c17575f8515613c005750838201355b5f19600387901b1c1916600186901b178355610e78565b5f83815260209020601f19861690835b82811015613c475786850135825560209485019460019092019101613c27565b5086821015613c63575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f82601f830112613c84575f80fd5b8151613c9261350e826134db565b818152846020838601011115613ca6575f80fd5b611811826020830160208701613277565b5f60208284031215613cc7575f80fd5b81516001600160401b03811115613cdc575f80fd5b61181184828501613c75565b61ffff85168152608060208201525f613d046080830186613299565b6001600160401b03851660408401528281036060840152613b768185613299565b5f60208284031215613d35575f80fd5b5051919050565b61ffff84168152606060208201525f613d586060830185613299565b9050826040830152949350505050565b604081525f613d7a6040830185613299565b90508260208301529392505050565b80820180821115610d3557610d356139fc565b5f8251613dad818460208701613277565b9190910192915050565b61ffff8616815260a060208201525f613dd360a0830187613299565b6001600160401b03861660408401528281036060840152613df48186613299565b90508281036080840152613e088185613299565b98975050505050505050565b61ffff8716815260c060208201525f613e3060c0830188613299565b8281036040840152613e428188613299565b6001600160a01b0387811660608601528616608085015283810360a085015290506139b08185613299565b5f805f60608486031215613e7f575f80fd5b8351613e8a81613153565b60208501519093506001600160401b03811115613ea5575f80fd5b613eb186828701613c75565b92505060408401519050925092509256fe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc111388274dd962a0529050efb131321f60015c2ab1a99387d94540f430037b00a164736f6c6343000814000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7
-----Decoded View---------------
Arg [0] : lzEndpoint (address): 0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.