ETH Price: $2,257.04 (-0.64%)

Transaction Decoder

Block:
21414905 at Dec-16-2024 11:53:35 AM +UTC
Transaction Fee:
0.001040870425434898 ETH $2.35
Gas Used:
60,938 Gas / 17.080810421 Gwei

Emitted Events:

222 TransparentUpgradeableProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000002c359478b769c8963ca0567d6785c1984de07487, 0x00000000000000000000000027b090802a0b683dcb28a223f986373e24f3dc4a, 0000000000000000000000000000000000000000000000022b1c8c1227a00000 )

Account State Difference:

  Address   Before After State Difference Code
0x2C359478...84de07487
0.005956387974011523 Eth
Nonce: 1323
0.004915517548576625 Eth
Nonce: 1324
0.001040870425434898
0x39D5313C...6145a9bd2
(Titan Builder)
5.541373714454945309 Eth5.541471245723945309 Eth0.000097531269

Execution Trace

TransparentUpgradeableProxy.a9059cbb( )
  • Empyreal.transfer( to=0x27B090802A0b683dCB28a223f986373E24f3Dc4A, value=40000000000000000000 ) => ( True )
    File 1 of 2: TransparentUpgradeableProxy
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
    pragma solidity ^0.8.20;
    import {Context} from "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * 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 Ownable is Context {
        address private _owner;
        /**
         * @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.
         */
        constructor(address initialOwner) {
            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) {
            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 {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
     */
    interface IERC1967 {
        /**
         * @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);
    }
    // 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) (proxy/ERC1967/ERC1967Proxy.sol)
    pragma solidity ^0.8.20;
    import {Proxy} from "../Proxy.sol";
    import {ERC1967Utils} from "./ERC1967Utils.sol";
    /**
     * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
     * implementation address that can be changed. This address is stored in storage in the location specified by
     * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
     * implementation behind the proxy.
     */
    contract ERC1967Proxy is Proxy {
        /**
         * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
         *
         * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
         * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
         *
         * Requirements:
         *
         * - If `data` is empty, `msg.value` must be zero.
         */
        constructor(address implementation, bytes memory _data) payable {
            ERC1967Utils.upgradeToAndCall(implementation, _data);
        }
        /**
         * @dev Returns the current implementation address.
         *
         * 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.
         * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
         */
        function _implementation() internal view virtual override returns (address) {
            return ERC1967Utils.getImplementation();
        }
    }
    // 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) (proxy/Proxy.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
     * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
     * be specified by overriding the virtual {_implementation} function.
     *
     * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
     * different contract through the {_delegate} function.
     *
     * The success and return data of the delegated call will be returned back to the caller of the proxy.
     */
    abstract contract Proxy {
        /**
         * @dev Delegates the current call to `implementation`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _delegate(address implementation) internal virtual {
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 {
                    revert(0, returndatasize())
                }
                default {
                    return(0, returndatasize())
                }
            }
        }
        /**
         * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
         * function and {_fallback} should delegate.
         */
        function _implementation() internal view virtual returns (address);
        /**
         * @dev Delegates the current call to the address returned by `_implementation()`.
         *
         * This function does not return to its internal call site, it will return directly to the external caller.
         */
        function _fallback() internal virtual {
            _delegate(_implementation());
        }
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
         * function in the contract matches the call data.
         */
        fallback() external payable virtual {
            _fallback();
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
    pragma solidity ^0.8.20;
    import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
    import {Ownable} from "../../access/Ownable.sol";
    /**
     * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
     * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
     */
    contract ProxyAdmin is Ownable {
        /**
         * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
         * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
         * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
         * If the getter returns `"5.0.0"`, only `upgradeAndCall(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 Sets the initial owner who can perform upgrades.
         */
        constructor(address initialOwner) Ownable(initialOwner) {}
        /**
         * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
         * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
         *
         * Requirements:
         *
         * - This contract must be the admin of `proxy`.
         * - If `data` is empty, `msg.value` must be zero.
         */
        function upgradeAndCall(
            ITransparentUpgradeableProxy proxy,
            address implementation,
            bytes memory data
        ) public payable virtual onlyOwner {
            proxy.upgradeToAndCall{value: msg.value}(implementation, data);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
    pragma solidity ^0.8.20;
    import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
    import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
    import {IERC1967} from "../../interfaces/IERC1967.sol";
    import {ProxyAdmin} from "./ProxyAdmin.sol";
    /**
     * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
     * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
     * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
     * include them in the ABI so this interface must be used to interact with it.
     */
    interface ITransparentUpgradeableProxy is IERC1967 {
        function upgradeToAndCall(address, bytes calldata) external payable;
    }
    /**
     * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
     *
     * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
     * clashing], which can potentially be used in an attack, this contract uses the
     * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
     * things that go hand in hand:
     *
     * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
     * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
     * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
     * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
     * the proxy admin cannot fallback to the target implementation.
     *
     * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a
     * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to
     * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and
     * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
     * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
     *
     * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
     * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
     * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
     * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
     * implementation.
     *
     * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
     * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
     *
     * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
     * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
     * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
     * undesirable state where the admin slot is different from the actual admin.
     *
     * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
     * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
     * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
     * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
     */
    contract TransparentUpgradeableProxy is ERC1967Proxy {
        // An immutable address for the admin to avoid unnecessary SLOADs before each call
        // at the expense of removing the ability to change the admin once it's set.
        // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
        // with its own ability to transfer the permissions to another account.
        address private immutable _admin;
        /**
         * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
         */
        error ProxyDeniedAdminAccess();
        /**
         * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
         * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
         * {ERC1967Proxy-constructor}.
         */
        constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
            _admin = address(new ProxyAdmin(initialOwner));
            // Set the storage value and emit an event for ERC-1967 compatibility
            ERC1967Utils.changeAdmin(_proxyAdmin());
        }
        /**
         * @dev Returns the admin of this proxy.
         */
        function _proxyAdmin() internal virtual returns (address) {
            return _admin;
        }
        /**
         * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
         */
        function _fallback() internal virtual override {
            if (msg.sender == _proxyAdmin()) {
                if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                    revert ProxyDeniedAdminAccess();
                } else {
                    _dispatchUpgradeToAndCall();
                }
            } else {
                super._fallback();
            }
        }
        /**
         * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
         *
         * Requirements:
         *
         * - If `data` is empty, `msg.value` must be zero.
         */
        function _dispatchUpgradeToAndCall() private {
            (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
            ERC1967Utils.upgradeToAndCall(newImplementation, data);
        }
    }
    // 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/Context.sol)
    pragma solidity ^0.8.20;
    /**
     * @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 Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // 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
            }
        }
    }
    

    File 2 of 2: Empyreal
    // 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.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);
    }
    // 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
    // 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
    // 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) (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) (token/ERC20/extensions/ERC20Burnable.sol)
    pragma solidity ^0.8.20;
    import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
    import {ContextUpgradeable} from "../../../utils/ContextUpgradeable.sol";
    import {Initializable} from "../../../proxy/utils/Initializable.sol";
    /**
     * @dev Extension of {ERC20} that allows token holders to destroy both their own
     * tokens and those that they have an allowance for, in a way that can be
     * recognized off-chain (via event analysis).
     */
    abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable {
        function __ERC20Burnable_init() internal onlyInitializing {
        }
        function __ERC20Burnable_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev Destroys a `value` amount of tokens from the caller.
         *
         * See {ERC20-_burn}.
         */
        function burn(uint256 value) public virtual {
            _burn(_msgSender(), value);
        }
        /**
         * @dev Destroys a `value` amount of tokens from `account`, deducting from
         * the caller's allowance.
         *
         * See {ERC20-_burn} and {ERC20-allowance}.
         *
         * Requirements:
         *
         * - the caller must have allowance for ``accounts``'s tokens of at least
         * `value`.
         */
        function burnFrom(address account, uint256 value) public virtual {
            _spendAllowance(account, _msgSender(), value);
            _burn(account, value);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (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;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
    pragma solidity ^0.8.20;
    import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
    import {Initializable} from "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165 {
        function __ERC165_init() internal onlyInitializing {
        }
        function __ERC165_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
    pragma solidity ^0.8.20;
    import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
    import {Initializable} from "../proxy/utils/Initializable.sol";
    /**
     * @dev Contract module which allows children to implement an emergency stop
     * mechanism that can be triggered by an authorized account.
     *
     * This module is used through inheritance. It will make available the
     * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
     * the functions of your contract. Note that they will not be pausable by
     * simply including this module, only once the modifiers are put in place.
     */
    abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
        /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
        struct PausableStorage {
            bool _paused;
        }
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
        function _getPausableStorage() private pure returns (PausableStorage storage $) {
            assembly {
                $.slot := PausableStorageLocation
            }
        }
        /**
         * @dev Emitted when the pause is triggered by `account`.
         */
        event Paused(address account);
        /**
         * @dev Emitted when the pause is lifted by `account`.
         */
        event Unpaused(address account);
        /**
         * @dev The operation failed because the contract is paused.
         */
        error EnforcedPause();
        /**
         * @dev The operation failed because the contract is not paused.
         */
        error ExpectedPause();
        /**
         * @dev Initializes the contract in unpaused state.
         */
        function __Pausable_init() internal onlyInitializing {
            __Pausable_init_unchained();
        }
        function __Pausable_init_unchained() internal onlyInitializing {
            PausableStorage storage $ = _getPausableStorage();
            $._paused = false;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        modifier whenNotPaused() {
            _requireNotPaused();
            _;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        modifier whenPaused() {
            _requirePaused();
            _;
        }
        /**
         * @dev Returns true if the contract is paused, and false otherwise.
         */
        function paused() public view virtual returns (bool) {
            PausableStorage storage $ = _getPausableStorage();
            return $._paused;
        }
        /**
         * @dev Throws if the contract is paused.
         */
        function _requireNotPaused() internal view virtual {
            if (paused()) {
                revert EnforcedPause();
            }
        }
        /**
         * @dev Throws if the contract is not paused.
         */
        function _requirePaused() internal view virtual {
            if (!paused()) {
                revert ExpectedPause();
            }
        }
        /**
         * @dev Triggers stopped state.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        function _pause() internal virtual whenNotPaused {
            PausableStorage storage $ = _getPausableStorage();
            $._paused = true;
            emit Paused(_msgSender());
        }
        /**
         * @dev Returns to normal state.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        function _unpause() internal virtual whenPaused {
            PausableStorage storage $ = _getPausableStorage();
            $._paused = false;
            emit Unpaused(_msgSender());
        }
    }
    // 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) (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.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) (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.8.0;
    import "./OFTCoreV2Initializable.sol";
    import "./OFT/interfaces/IOFTV2.sol";
    import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
    abstract contract BaseOFTV2Initializable is
        OFTCoreV2Initializable,
        ERC165Upgradeable,
        IOFTV2
    {
        /************************************************************************
         * public functions
         ************************************************************************/
        function sendFrom(
            address _from,
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            LzCallParams calldata _callParams
        ) public payable virtual override {
            _send(
                _from,
                _dstChainId,
                _toAddress,
                _amount,
                _callParams.refundAddress,
                _callParams.zroPaymentAddress,
                _callParams.adapterParams
            );
        }
        function sendAndCall(
            address _from,
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bytes calldata _payload,
            uint64 _dstGasForCall,
            LzCallParams calldata _callParams
        ) public payable virtual override {
            _sendAndCall(
                _from,
                _dstChainId,
                _toAddress,
                _amount,
                _payload,
                _dstGasForCall,
                _callParams.refundAddress,
                _callParams.zroPaymentAddress,
                _callParams.adapterParams
            );
        }
        /************************************************************************
         * public view functions
         ************************************************************************/
        function supportsInterface(
            bytes4 interfaceId
        )
            public
            view
            virtual
            override(ERC165Upgradeable, IERC165)
            returns (bool)
        {
            return
                interfaceId == type(IOFTV2).interfaceId ||
                super.supportsInterface(interfaceId);
        }
        function estimateSendFee(
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bool _useZro,
            bytes calldata _adapterParams
        ) public view virtual override returns (uint nativeFee, uint zroFee) {
            return
                _estimateSendFee(
                    _dstChainId,
                    _toAddress,
                    _amount,
                    _useZro,
                    _adapterParams
                );
        }
        function estimateSendAndCallFee(
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bytes calldata _payload,
            uint64 _dstGasForCall,
            bool _useZro,
            bytes calldata _adapterParams
        ) public view virtual override returns (uint nativeFee, uint zroFee) {
            return
                _estimateSendAndCallFee(
                    _dstChainId,
                    _toAddress,
                    _amount,
                    _payload,
                    _dstGasForCall,
                    _useZro,
                    _adapterParams
                );
        }
        function circulatingSupply() public view virtual override returns (uint);
        function token() public view virtual override returns (address);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.0;
    import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
    import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
    import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
    import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
    import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
    import "./OFTV2Initializable.sol";
    contract Empyreal is
        Initializable,
        ERC20BurnableUpgradeable,
        PausableUpgradeable,
        OwnableUpgradeable,
        OFTV2Initializable
    {
        /// @custom:oz-upgrades-unsafe-allow constructor
        constructor() {
            _disableInitializers();
        }
        function initialize(address _owner) public virtual initializer {
            __ERC20_init("Empyreal", "EMP");
            __ERC20Burnable_init();
            __Pausable_init();
            __Ownable_init(_owner);
            // chain 101
            lzEndpoint = ILayerZeroEndpoint(
                address(0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675)
            );
            // start with contract paused
            _pause();
        }
        function pause() public onlyOwner {
            _pause();
        }
        function unpause() public onlyOwner {
            _unpause();
        }
        function _update(
            address from,
            address to,
            uint256 amount
        ) internal virtual override {
            if (tx.origin != owner()) {
                require(!paused(), "Empyreal: token transfer while paused");
            }
            super._update(from, to, amount);
        }
        /*
         * LZ Methods
         */
        function circulatingSupply() public view virtual override returns (uint) {
            return totalSupply();
        }
        /************************************************************************
         * internal functions
         ************************************************************************/
        function _debitFrom(
            address _from,
            uint16,
            bytes32,
            uint _amount
        ) internal virtual override returns (uint) {
            address spender = _msgSender();
            if (_from != spender) _spendAllowance(_from, spender, _amount);
            _burn(_from, _amount);
            return _amount;
        }
        function _creditTo(
            uint16,
            address _toAddress,
            uint _amount
        ) internal virtual override returns (uint) {
            _mint(_toAddress, _amount);
            return _amount;
        }
        function _transferFrom(
            address _from,
            address _to,
            uint _amount
        ) internal virtual override returns (uint) {
            address spender = _msgSender();
            // if transfer from this contract, no need to check allowance
            if (_from != address(this) && _from != spender)
                _spendAllowance(_from, spender, _amount);
            _transfer(_from, _to, _amount);
            return _amount;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.5.0;
    import {IERC165} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
    /**
     * @dev Interface of the IOFT core standard
     */
    interface ICommonOFT is IERC165 {
        struct LzCallParams {
            address payable refundAddress;
            address zroPaymentAddress;
            bytes adapterParams;
        }
        /**
         * @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,
            bytes32 _toAddress,
            uint _amount,
            bool _useZro,
            bytes calldata _adapterParams
        ) external view returns (uint nativeFee, uint zroFee);
        function estimateSendAndCallFee(
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bytes calldata _payload,
            uint64 _dstGasForCall,
            bool _useZro,
            bytes calldata _adapterParams
        ) external view returns (uint nativeFee, uint zroFee);
        /**
         * @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);
    }
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity >=0.5.0;
    interface IOFTReceiverV2 {
        /**
         * @dev Called by the OFT contract when tokens are received from source chain.
         * @param _srcChainId The chain id of the source chain.
         * @param _srcAddress The address of the OFT token contract on the source chain.
         * @param _nonce The nonce of the transaction on the source chain.
         * @param _from The address of the account who calls the sendAndCall() on the source chain.
         * @param _amount The amount of tokens to transfer.
         * @param _payload Additional data with no specified format.
         */
        function onOFTReceived(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes32 _from, uint _amount, bytes calldata _payload) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.5.0;
    import "./ICommonOFT.sol";
    /**
     * @dev Interface of the IOFT core standard
     */
    interface IOFTV2 is ICommonOFT {
        /**
         * @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, bytes32 _toAddress, uint _amount, LzCallParams calldata _callParams) external payable;
        function sendAndCall(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, bytes calldata _payload, uint64 _dstGasForCall, LzCallParams calldata _callParams) external payable;
    }
    // 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.0;
    import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
    import "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroReceiver.sol";
    import "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol";
    import "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol";
    import "@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol";
    /*
     * a generic LzReceiver implementation
     */
    abstract contract LzApp 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
        uint public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;
        ILayerZeroEndpoint public lzEndpoint;
        mapping(uint16 => bytes) public trustedRemoteLookup;
        mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
        mapping(uint16 => uint) public payloadSizeLimitLookup;
        address public precrime;
        event SetPrecrime(address precrime);
        event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
        event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
        event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);
        function lzReceive(
            uint16 _srcChainId,
            bytes calldata _srcAddress,
            uint64 _nonce,
            bytes calldata _payload
        ) public virtual override {
            // 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);
        }
        // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging
        function _blockingLzReceive(
            uint16 _srcChainId,
            bytes memory _srcAddress,
            uint64 _nonce,
            bytes memory _payload
        ) internal virtual;
        function _lzSend(
            uint16 _dstChainId,
            bytes memory _payload,
            address payable _refundAddress,
            address _zroPaymentAddress,
            bytes memory _adapterParams,
            uint _nativeFee
        ) internal virtual {
            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
            );
        }
        function _checkGasLimit(
            uint16 _dstChainId,
            uint16 _type,
            bytes memory _adapterParams,
            uint _extraGas
        ) internal view virtual {
            uint providedGasLimit = _getGasLimit(_adapterParams);
            uint minGasLimit = minDstGasLookup[_dstChainId][_type];
            require(minGasLimit > 0, "LzApp: minGasLimit not set");
            require(
                providedGasLimit >= minGasLimit + _extraGas,
                "LzApp: gas limit is too low"
            );
        }
        function _getGasLimit(
            bytes memory _adapterParams
        ) internal pure virtual returns (uint gasLimit) {
            require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
            assembly {
                gasLimit := mload(add(_adapterParams, 34))
            }
        }
        function _checkPayloadSize(
            uint16 _dstChainId,
            uint _payloadSize
        ) internal view virtual {
            uint 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"
            );
        }
        //---------------------------UserApplication config----------------------------------------
        function getConfig(
            uint16 _version,
            uint16 _chainId,
            address,
            uint _configType
        ) external view returns (bytes memory) {
            return
                lzEndpoint.getConfig(
                    _version,
                    _chainId,
                    address(this),
                    _configType
                );
        }
        // generic config for LayerZero user Application
        function setConfig(
            uint16 _version,
            uint16 _chainId,
            uint _configType,
            bytes calldata _config
        ) external override onlyOwner {
            lzEndpoint.setConfig(_version, _chainId, _configType, _config);
        }
        function setSendVersion(uint16 _version) external override onlyOwner {
            lzEndpoint.setSendVersion(_version);
        }
        function setReceiveVersion(uint16 _version) external override onlyOwner {
            lzEndpoint.setReceiveVersion(_version);
        }
        function forceResumeReceive(
            uint16 _srcChainId,
            bytes calldata _srcAddress
        ) external override onlyOwner {
            lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
        }
        // _path = abi.encodePacked(remoteAddress, localAddress)
        // this function set the trusted path for the cross-chain communication
        function setTrustedRemote(
            uint16 _remoteChainId,
            bytes calldata _path
        ) external onlyOwner {
            trustedRemoteLookup[_remoteChainId] = _path;
            emit SetTrustedRemote(_remoteChainId, _path);
        }
        function setTrustedRemoteAddress(
            uint16 _remoteChainId,
            bytes calldata _remoteAddress
        ) external onlyOwner {
            trustedRemoteLookup[_remoteChainId] = abi.encodePacked(
                _remoteAddress,
                address(this)
            );
            emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);
        }
        function getTrustedRemoteAddress(
            uint16 _remoteChainId
        ) external view returns (bytes memory) {
            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)
        }
        function setPrecrime(address _precrime) external onlyOwner {
            precrime = _precrime;
            emit SetPrecrime(_precrime);
        }
        function setMinDstGas(
            uint16 _dstChainId,
            uint16 _packetType,
            uint _minGas
        ) external onlyOwner {
            minDstGasLookup[_dstChainId][_packetType] = _minGas;
            emit SetMinDstGas(_dstChainId, _packetType, _minGas);
        }
        // if the size is 0, it means default size limit
        function setPayloadSizeLimit(
            uint16 _dstChainId,
            uint _size
        ) external onlyOwner {
            payloadSizeLimitLookup[_dstChainId] = _size;
        }
        //--------------------------- VIEW FUNCTION ----------------------------------------
        function isTrustedRemote(
            uint16 _srcChainId,
            bytes calldata _srcAddress
        ) external view returns (bool) {
            bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
            return keccak256(trustedSource) == keccak256(_srcAddress);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./LzApp.sol";
    import "../libraries/ExcessivelySafeCall.sol";
    /*
     * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel
     * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking
     * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)
     */
    abstract contract NonblockingLzApp is LzApp {
        using ExcessivelySafeCall for address;
        mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32)))
            public failedMessages;
        event MessageFailed(
            uint16 _srcChainId,
            bytes _srcAddress,
            uint64 _nonce,
            bytes _payload,
            bytes _reason
        );
        event RetryMessageSuccess(
            uint16 _srcChainId,
            bytes _srcAddress,
            uint64 _nonce,
            bytes32 _payloadHash
        );
        // overriding the virtual function in LzReceiver
        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
                )
            );
            if (!success) {
                _storeFailedMessage(
                    _srcChainId,
                    _srcAddress,
                    _nonce,
                    _payload,
                    reason
                );
            }
        }
        function _storeFailedMessage(
            uint16 _srcChainId,
            bytes memory _srcAddress,
            uint64 _nonce,
            bytes memory _payload,
            bytes memory _reason
        ) internal virtual {
            failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);
            emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);
        }
        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);
        }
        //@notice override this function
        function _nonblockingLzReceive(
            uint16 _srcChainId,
            bytes memory _srcAddress,
            uint64 _nonce,
            bytes memory _payload
        ) internal virtual;
        function retryMessage(
            uint16 _srcChainId,
            bytes calldata _srcAddress,
            uint64 _nonce,
            bytes calldata _payload
        ) public payable virtual {
            // assert there is message to retry
            bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];
            require(
                payloadHash != bytes32(0),
                "NonblockingLzApp: no stored message"
            );
            require(
                keccak256(_payload) == payloadHash,
                "NonblockingLzApp: invalid payload"
            );
            // clear the stored message
            failedMessages[_srcChainId][_srcAddress][_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.8.0;
    import "./OFT/lzApp/NonblockingLzApp.sol";
    import "./OFT/libraries/ExcessivelySafeCall.sol";
    import "./OFT/interfaces/ICommonOFT.sol";
    import "./OFT/interfaces/IOFTReceiverV2.sol";
    abstract contract OFTCoreV2Initializable is NonblockingLzApp {
        using BytesLib for bytes;
        using ExcessivelySafeCall for address;
        uint public constant NO_EXTRA_GAS = 0;
        // packet type
        uint8 public constant PT_SEND = 0;
        uint8 public constant PT_SEND_AND_CALL = 1;
        uint8 public constant sharedDecimals = 8;
        mapping(uint16 => mapping(bytes => mapping(uint64 => bool)))
            public creditedPackets;
        /**
         * @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,
            bytes32 indexed _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 CallOFTReceivedSuccess(
            uint16 indexed _srcChainId,
            bytes _srcAddress,
            uint64 _nonce,
            bytes32 _hash
        );
        event NonContractAddress(address _address);
        /************************************************************************
         * public functions
         ************************************************************************/
        function callOnOFTReceived(
            uint16 _srcChainId,
            bytes calldata _srcAddress,
            uint64 _nonce,
            bytes32 _from,
            address _to,
            uint _amount,
            bytes calldata _payload,
            uint _gasForCall
        ) public virtual {
            require(
                _msgSender() == address(this),
                "OFTCore: caller must be OFTCore"
            );
            // send
            _amount = _transferFrom(address(this), _to, _amount);
            emit ReceiveFromChain(_srcChainId, _to, _amount);
            // call
            IOFTReceiverV2(_to).onOFTReceived{gas: _gasForCall}(
                _srcChainId,
                _srcAddress,
                _nonce,
                _from,
                _amount,
                _payload
            );
        }
        /************************************************************************
         * internal functions
         ************************************************************************/
        function _estimateSendFee(
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bool _useZro,
            bytes memory _adapterParams
        ) internal view virtual returns (uint nativeFee, uint zroFee) {
            // mock the payload for sendFrom()
            bytes memory payload = _encodeSendPayload(_toAddress, _ld2sd(_amount));
            return
                lzEndpoint.estimateFees(
                    _dstChainId,
                    address(this),
                    payload,
                    _useZro,
                    _adapterParams
                );
        }
        function _estimateSendAndCallFee(
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bytes memory _payload,
            uint64 _dstGasForCall,
            bool _useZro,
            bytes memory _adapterParams
        ) internal view virtual returns (uint nativeFee, uint zroFee) {
            // mock the payload for sendAndCall()
            bytes memory payload = _encodeSendAndCallPayload(
                msg.sender,
                _toAddress,
                _ld2sd(_amount),
                _payload,
                _dstGasForCall
            );
            return
                lzEndpoint.estimateFees(
                    _dstChainId,
                    address(this),
                    payload,
                    _useZro,
                    _adapterParams
                );
        }
        function _nonblockingLzReceive(
            uint16 _srcChainId,
            bytes memory _srcAddress,
            uint64 _nonce,
            bytes memory _payload
        ) internal virtual override {
            uint8 packetType = _payload.toUint8(0);
            if (packetType == PT_SEND) {
                _sendAck(_srcChainId, _srcAddress, _nonce, _payload);
            } else if (packetType == PT_SEND_AND_CALL) {
                _sendAndCallAck(_srcChainId, _srcAddress, _nonce, _payload);
            } else {
                revert("OFTCore: unknown packet type");
            }
        }
        function _send(
            address _from,
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            address payable _refundAddress,
            address _zroPaymentAddress,
            bytes memory _adapterParams
        ) internal virtual returns (uint amount) {
            _checkGasLimit(_dstChainId, PT_SEND, _adapterParams, NO_EXTRA_GAS);
            (amount, ) = _removeDust(_amount);
            amount = _debitFrom(_from, _dstChainId, _toAddress, amount); // amount returned should not have dust
            require(amount > 0, "OFTCore: amount too small");
            bytes memory lzPayload = _encodeSendPayload(_toAddress, _ld2sd(amount));
            _lzSend(
                _dstChainId,
                lzPayload,
                _refundAddress,
                _zroPaymentAddress,
                _adapterParams,
                msg.value
            );
            emit SendToChain(_dstChainId, _from, _toAddress, amount);
        }
        function _sendAck(
            uint16 _srcChainId,
            bytes memory,
            uint64,
            bytes memory _payload
        ) internal virtual {
            (address to, uint64 amountSD) = _decodeSendPayload(_payload);
            if (to == address(0)) {
                to = address(0xdead);
            }
            uint amount = _sd2ld(amountSD);
            amount = _creditTo(_srcChainId, to, amount);
            emit ReceiveFromChain(_srcChainId, to, amount);
        }
        function _sendAndCall(
            address _from,
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount,
            bytes memory _payload,
            uint64 _dstGasForCall,
            address payable _refundAddress,
            address _zroPaymentAddress,
            bytes memory _adapterParams
        ) internal virtual returns (uint amount) {
            _checkGasLimit(
                _dstChainId,
                PT_SEND_AND_CALL,
                _adapterParams,
                _dstGasForCall
            );
            (amount, ) = _removeDust(_amount);
            amount = _debitFrom(_from, _dstChainId, _toAddress, amount);
            require(amount > 0, "OFTCore: amount too small");
            // encode the msg.sender into the payload instead of _from
            bytes memory lzPayload = _encodeSendAndCallPayload(
                msg.sender,
                _toAddress,
                _ld2sd(amount),
                _payload,
                _dstGasForCall
            );
            _lzSend(
                _dstChainId,
                lzPayload,
                _refundAddress,
                _zroPaymentAddress,
                _adapterParams,
                msg.value
            );
            emit SendToChain(_dstChainId, _from, _toAddress, amount);
        }
        function _sendAndCallAck(
            uint16 _srcChainId,
            bytes memory _srcAddress,
            uint64 _nonce,
            bytes memory _payload
        ) internal virtual {
            (
                bytes32 from,
                address to,
                uint64 amountSD,
                bytes memory payloadForCall,
                uint64 gasForCall
            ) = _decodeSendAndCallPayload(_payload);
            bool credited = creditedPackets[_srcChainId][_srcAddress][_nonce];
            uint amount = _sd2ld(amountSD);
            // credit to this contract first, and then transfer to receiver only if callOnOFTReceived() succeeds
            if (!credited) {
                amount = _creditTo(_srcChainId, address(this), amount);
                creditedPackets[_srcChainId][_srcAddress][_nonce] = true;
            }
            if (!_isContract(to)) {
                emit NonContractAddress(to);
                return;
            }
            // workaround for stack too deep
            uint16 srcChainId = _srcChainId;
            bytes memory srcAddress = _srcAddress;
            uint64 nonce = _nonce;
            bytes memory payload = _payload;
            bytes32 from_ = from;
            address to_ = to;
            uint amount_ = amount;
            bytes memory payloadForCall_ = payloadForCall;
            // no gas limit for the call if retry
            uint gas = credited ? gasleft() : gasForCall;
            (bool success, bytes memory reason) = address(this).excessivelySafeCall(
                gasleft(),
                150,
                abi.encodeWithSelector(
                    this.callOnOFTReceived.selector,
                    srcChainId,
                    srcAddress,
                    nonce,
                    from_,
                    to_,
                    amount_,
                    payloadForCall_,
                    gas
                )
            );
            if (success) {
                bytes32 hash = keccak256(payload);
                emit CallOFTReceivedSuccess(srcChainId, srcAddress, nonce, hash);
            } else {
                // store the failed message into the nonblockingLzApp
                _storeFailedMessage(srcChainId, srcAddress, nonce, payload, reason);
            }
        }
        function _isContract(address _account) internal view returns (bool) {
            return _account.code.length > 0;
        }
        function _ld2sd(uint _amount) internal view virtual returns (uint64) {
            uint amountSD = _amount / _ld2sdRate();
            require(amountSD <= type(uint64).max, "OFTCore: amountSD overflow");
            return uint64(amountSD);
        }
        function _sd2ld(uint64 _amountSD) internal view virtual returns (uint) {
            return _amountSD * _ld2sdRate();
        }
        function _removeDust(
            uint _amount
        ) internal view virtual returns (uint amountAfter, uint dust) {
            dust = _amount % _ld2sdRate();
            amountAfter = _amount - dust;
        }
        function _encodeSendPayload(
            bytes32 _toAddress,
            uint64 _amountSD
        ) internal view virtual returns (bytes memory) {
            return abi.encodePacked(PT_SEND, _toAddress, _amountSD);
        }
        function _decodeSendPayload(
            bytes memory _payload
        ) internal view virtual returns (address to, uint64 amountSD) {
            require(
                _payload.toUint8(0) == PT_SEND && _payload.length == 41,
                "OFTCore: invalid payload"
            );
            to = _payload.toAddress(13); // drop the first 12 bytes of bytes32
            amountSD = _payload.toUint64(33);
        }
        function _encodeSendAndCallPayload(
            address _from,
            bytes32 _toAddress,
            uint64 _amountSD,
            bytes memory _payload,
            uint64 _dstGasForCall
        ) internal view virtual returns (bytes memory) {
            return
                abi.encodePacked(
                    PT_SEND_AND_CALL,
                    _toAddress,
                    _amountSD,
                    _addressToBytes32(_from),
                    _dstGasForCall,
                    _payload
                );
        }
        function _decodeSendAndCallPayload(
            bytes memory _payload
        )
            internal
            view
            virtual
            returns (
                bytes32 from,
                address to,
                uint64 amountSD,
                bytes memory payload,
                uint64 dstGasForCall
            )
        {
            require(
                _payload.toUint8(0) == PT_SEND_AND_CALL,
                "OFTCore: invalid payload"
            );
            to = _payload.toAddress(13); // drop the first 12 bytes of bytes32
            amountSD = _payload.toUint64(33);
            from = _payload.toBytes32(41);
            dstGasForCall = _payload.toUint64(73);
            payload = _payload.slice(81, _payload.length - 81);
        }
        function _addressToBytes32(
            address _address
        ) internal pure virtual returns (bytes32) {
            return bytes32(uint(uint160(_address)));
        }
        function _debitFrom(
            address _from,
            uint16 _dstChainId,
            bytes32 _toAddress,
            uint _amount
        ) internal virtual returns (uint);
        function _creditTo(
            uint16 _srcChainId,
            address _toAddress,
            uint _amount
        ) internal virtual returns (uint);
        function _transferFrom(
            address _from,
            address _to,
            uint _amount
        ) internal virtual returns (uint);
        function _ld2sdRate() internal view virtual returns (uint);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./BaseOFTV2Initializable.sol";
    abstract contract OFTV2Initializable is BaseOFTV2Initializable {
        uint internal constant ld2sdRate = 10 ** 8;
        /************************************************************************
         * public functions
         ************************************************************************/
        function token() public view virtual override returns (address) {
            return address(this);
        }
        function _ld2sdRate() internal view virtual override returns (uint) {
            return ld2sdRate;
        }
    }