M Price: $1.53 (+0.39%)

Contract

0x25aB3Efd52e6470681CE037cD546Dc60726948D3
Transaction Hash
Block
From
To
Direct Release49837322026-02-17 18:53:5714 hrs ago1771354437IN
0x25aB3Efd...0726948D3
0 M0.116232271,502
Direct Release49809252026-02-17 13:26:2819 hrs ago1771334788IN
0x25aB3Efd...0726948D3
0 M0.116232271,502
Direct Execute S...49808152026-02-17 13:13:3819 hrs ago1771334018IN
0x25aB3Efd...0726948D3
2,570 M0.094430741,502
Direct Execute S...49789932026-02-17 9:41:0423 hrs ago1771321264IN
0x25aB3Efd...0726948D3
1,750 M0.094412711,502
Direct Execute S...49766102026-02-17 5:03:0328 hrs ago1771304583IN
0x25aB3Efd...0726948D3
2,089 M0.094430741,502
Direct Release49763732026-02-17 4:35:2428 hrs ago1771302924IN
0x25aB3Efd...0726948D3
0 M0.116232271,502
Direct Release49756202026-02-17 3:07:3330 hrs ago1771297653IN
0x25aB3Efd...0726948D3
0 M0.116250291,502
Direct Release49715242026-02-16 19:09:4138 hrs ago1771268981IN
0x25aB3Efd...0726948D3
0 M0.116214241,502
Direct Execute S...49690372026-02-16 14:19:3242 hrs ago1771251572IN
0x25aB3Efd...0726948D3
2,098 M0.094455881,502.4
Direct Execute S...49665332026-02-16 9:27:2447 hrs ago1771234044IN
0x25aB3Efd...0726948D3
3.7 M0.094197931,502
Direct Execute S...49522442026-02-15 5:40:213 days ago1771134021IN
0x25aB3Efd...0726948D3
3.7 M0.09417991,502
Direct Execute S...49375172026-02-14 1:02:124 days ago1771030932IN
0x25aB3Efd...0726948D3
415.5 M0.094437851,502.4
Direct Release49292462026-02-13 8:57:145 days ago1770973034IN
0x25aB3Efd...0726948D3
0 M0.116232271,502
Direct Release49194512026-02-12 13:54:295 days ago1770904469IN
0x25aB3Efd...0726948D3
0 M0.116250291,502
Direct Release49136632026-02-12 2:39:136 days ago1770863953IN
0x25aB3Efd...0726948D3
0 M0.116250291,502
Direct Execute S...49061472026-02-11 12:02:216 days ago1770811341IN
0x25aB3Efd...0726948D3
24 M0.094197931,502
Direct Release48930232026-02-10 10:31:127 days ago1770719472IN
0x25aB3Efd...0726948D3
0 M0.116214241,502
Direct Release48928252026-02-10 10:08:067 days ago1770718086IN
0x25aB3Efd...0726948D3
0 M0.116250291,502
Direct Release48915832026-02-10 7:43:128 days ago1770709392IN
0x25aB3Efd...0726948D3
0 M0.116232271,502
Direct Release48887812026-02-10 2:16:188 days ago1770689778IN
0x25aB3Efd...0726948D3
0 M0.116214241,502
Direct Execute S...48815452026-02-09 12:12:068 days ago1770639126IN
0x25aB3Efd...0726948D3
25,900 M0.094233971,502
Direct Release48776132026-02-09 4:33:229 days ago1770611602IN
0x25aB3Efd...0726948D3
0 M0.116017481,502
Direct Release48776062026-02-09 4:32:339 days ago1770611553IN
0x25aB3Efd...0726948D3
0 M0.11603551,502
Direct Release48775902026-02-09 4:30:419 days ago1770611441IN
0x25aB3Efd...0726948D3
0 M0.11603551,502
Direct Execute S...48753612026-02-09 0:10:389 days ago1770595838IN
0x25aB3Efd...0726948D3
2,197 M0.094437851,502.4
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
49837322026-02-17 18:53:5714 hrs ago1771354437
0x25aB3Efd...0726948D3
5,892.434709 M
49809252026-02-17 13:26:2819 hrs ago1771334788
0x25aB3Efd...0726948D3
2,564.86257 M
49763732026-02-17 4:35:2428 hrs ago1771302924
0x25aB3Efd...0726948D3
4,794.556444 M
49756202026-02-17 3:07:3330 hrs ago1771297653
0x25aB3Efd...0726948D3
4,593.417439 M
49715242026-02-16 19:09:4138 hrs ago1771268981
0x25aB3Efd...0726948D3
2,995.284984 M
49292462026-02-13 8:57:145 days ago1770973034
0x25aB3Efd...0726948D3
792.266774 M
49194512026-02-12 13:54:295 days ago1770904469
0x25aB3Efd...0726948D3
8,900.389498 M
49136632026-02-12 2:39:136 days ago1770863953
0x25aB3Efd...0726948D3
4,798.224015 M
48930232026-02-10 10:31:127 days ago1770719472
0x25aB3Efd...0726948D3
2,995.29612 M
48928252026-02-10 10:08:067 days ago1770718086
0x25aB3Efd...0726948D3
4,494.461361 M
48915832026-02-10 7:43:128 days ago1770709392
0x25aB3Efd...0726948D3
3,495.672447 M
48887812026-02-10 2:16:188 days ago1770689778
0x25aB3Efd...0726948D3
2,895.18211 M
48776132026-02-09 4:33:229 days ago1770611602
0x25aB3Efd...0726948D3
39,960 M
48776062026-02-09 4:32:339 days ago1770611553
0x25aB3Efd...0726948D3
29,970 M
48775902026-02-09 4:30:419 days ago1770611441
0x25aB3Efd...0726948D3
29,970 M
48708312026-02-08 15:22:089 days ago1770564128
0x25aB3Efd...0726948D3
2,895.732828 M
48647342026-02-08 3:30:4910 days ago1770521449
0x25aB3Efd...0726948D3
2,201.387556 M
48647322026-02-08 3:30:3510 days ago1770521435
0x25aB3Efd...0726948D3
2,499.0984 M
48646892026-02-08 3:25:3410 days ago1770521134
0x25aB3Efd...0726948D3
841.999074 M
48644322026-02-08 2:55:3510 days ago1770519335
0x25aB3Efd...0726948D3
361.46439 M
48630172026-02-08 0:10:3010 days ago1770509430
0x25aB3Efd...0726948D3
4,596.399 M
48622802026-02-07 22:44:3110 days ago1770504271
0x25aB3Efd...0726948D3
5,894.349687 M
48618562026-02-07 21:55:0310 days ago1770501303
0x25aB3Efd...0726948D3
3,596.329663 M
48485682026-02-06 20:04:4711 days ago1770408287
0x25aB3Efd...0726948D3
5,892.885038 M
48445822026-02-06 12:19:4511 days ago1770380385
0x25aB3Efd...0726948D3
5,693.619207 M
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ProxyToMeson

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 100 runs

Other Settings:
istanbul EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import "./UpgradableMeson.sol";

contract ProxyToMeson is ERC1967Proxy {
  bytes4 private constant INITIALIZE_SELECTOR = bytes4(keccak256("initialize(address,address)"));

  constructor(address premiumManager) ERC1967Proxy(_deployImpl(), _encodeData(msg.sender, premiumManager)) {}

  function _deployImpl() private returns (address) {
    UpgradableMeson _impl = new UpgradableMeson();
    return address(_impl);
  }

  function _encodeData(address owner, address premiumManager) private pure returns (bytes memory) {
    return abi.encodeWithSelector(INITIALIZE_SELECTOR, owner, premiumManager);
  }
}

File 2 of 28 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 3 of 28 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {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 bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 5 of 28 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @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]
 * ```
 * 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 Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 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. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _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.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so 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.
     *
     * 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.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _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() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @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.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate that the this implementation remains valid after an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @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:
 * ```
 * 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(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 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
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @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.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.0;

import "../Proxy.sol";
import "./ERC1967Upgrade.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, ERC1967Upgrade {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
     * function call, and allows initializing the storage of the proxy like a Solidity constructor.
     */
    constructor(address _logic, bytes memory _data) payable {
        _upgradeToAndCall(_logic, _data, false);
    }

    /**
     * @dev Returns the current implementation address.
     */
    function _implementation() internal view virtual override returns (address impl) {
        return ERC1967Upgrade._getImplementation();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967Upgrade {
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @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 {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    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 {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {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 bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @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 {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @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 {
        _beforeFallback();
        _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();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overridden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
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 v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @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:
 * ```
 * 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(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 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
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title Interface for depositWithBeneficiary
interface IDepositWithBeneficiary {
  /// @notice Make a token transfer that the *signer* is paying tokens but benefits are given to the *beneficiary*
  /// @param token The contract address of the transferring token
  /// @param amount The amount of the transfer
  /// @param beneficiary The address that will receive benefits of this transfer
  /// @param data Extra data passed to the contract
  /// @return Returns true for a successful transfer.
  function depositWithBeneficiary(address token, uint256 amount, address beneficiary, uint64 data)
    payable external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

/// @title Minimal ERC20 interface for Uniswap
/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3
interface IERC20Minimal {
  /// @notice Returns the balance of a token
  /// @param account The account for which to look up the number of tokens it has, i.e. its balance
  /// @return The number of tokens held by the account
  function balanceOf(address account) external view returns (uint256);

  /// @notice Transfers the amount of token from the `msg.sender` to the recipient
  /// @param recipient The account that will receive the amount transferred
  /// @param amount The number of tokens to send from the sender to the recipient
  /// @return Returns true for a successful transfer, false for an unsuccessful transfer
  function transfer(address recipient, uint256 amount) external returns (bool);

  /// @notice Returns the current allowance given to a spender by an owner
  /// @param owner The account of the token owner
  /// @param spender The account of the token spender
  /// @return The current allowance granted by `owner` to `spender`
  function allowance(address owner, address spender) external view returns (uint256);

  /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount`
  /// @param spender The account which will be allowed to spend a given amount of the owners tokens
  /// @param amount The amount of tokens allowed to be used by `spender`
  /// @return Returns true for a successful approval, false for unsuccessful
  function approve(address spender, uint256 amount) external returns (bool);

  /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender`
  /// @param sender The account from which the transfer will be initiated
  /// @param recipient The recipient of the transfer
  /// @param amount The amount of the transfer
  /// @return Returns true for a successful transfer, false for unsuccessful
  function transferFrom(
      address sender,
      address recipient,
      uint256 amount
  ) external returns (bool);

  /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`.
  /// @param from The account from which the tokens were sent, i.e. the balance decreased
  /// @param to The account to which the tokens were sent, i.e. the balance increased
  /// @param value The amount of tokens that were transferred
  event Transfer(address indexed from, address indexed to, uint256 value);

  /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes.
  /// @param owner The account that approved spending of its tokens
  /// @param spender The account for which the spending allowance was modified
  /// @param value The new allowance from the owner to the spender
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "./Swap/MesonSwap.sol";
import "./Pools/MesonPools.sol";

/// @title MesonManager
/// @notice The class to store data related to management permissions of Meson
contract MesonManager is MesonSwap, MesonPools {
  /// @notice The admin of meson contract
  /// The owner has the permission to upgrade meson contract. In future versions,
  /// the management authority of meson contract will be decentralized.
  address internal _owner;

  /// @notice The manager to authorized fee waived swaps
  /// Only the premium manager can authorize the execution to release for fee waived swaps.
  /// This address is managed by Meson team.
  address internal _premiumManager;

  /// @dev This empty reserved space is put in place to allow future versions to
  /// add new variables without shifting down storage in the inheritance chain.
  /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  uint256[50] private __gap;

  event OwnerTransferred(address indexed prevOwner, address indexed newOwner);

  event PremiumManagerTransferred(address indexed prevPremiumManager, address indexed newPremiumManager);

  /// @notice The owner will also have the permission to add supported tokens
  function addSupportToken(address token, uint8 index) external onlyOwner {
    _addSupportToken(token, index);
  }

  /// @notice The owner will also have the permission to remove a supported tokens
  function removeSupportToken(uint8 index) external onlyOwner {
    _removeSupportToken(index);
  }

  /// @notice Add multiple tokens
  function addMultipleSupportedTokens(address[] memory tokens, uint8[] memory indexes) external onlyOwner {
    require(tokens.length == indexes.length, "Tokens and indexes should have the same length");
    for (uint8 i = 0; i < tokens.length; i++) {
      _addSupportToken(tokens[i], indexes[i]);
    }
  }

  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  function transferPremiumManager(address newPremiumManager) public {
    require(_isPremiumManager(), "Caller is not the premium manager");
    _transferPremiumManager(newPremiumManager);
  }

  function withdrawServiceFee(uint8 tokenIndex, uint256 amount, uint40 toPoolIndex) external onlyOwner {
    require(ownerOfPool[toPoolIndex] != address(0), "Pool index not registered");
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)] -= amount;
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, toPoolIndex)] += amount;
  }

  modifier onlyOwner() {
    require(_owner == _msgSender(), "Caller is not the owner");
    _;
  }

  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0), "New owner cannot be zero address");
    address prevOwner = _owner;
    _owner = newOwner;
    emit OwnerTransferred(prevOwner, newOwner);
  }

  function _isPremiumManager() internal view override(MesonSwap, MesonPools) returns (bool) {
    return _premiumManager == _msgSender();
  }

  function _transferPremiumManager(address newPremiumManager) internal {
    require(newPremiumManager != address(0), "New premium manager be zero address");
    address prevPremiumManager = _premiumManager;
    _premiumManager = newPremiumManager;
    emit PremiumManagerTransferred(prevPremiumManager, newPremiumManager);
  }

  function directSwap(uint256 encodedSwap, address recipient, bytes32 r, bytes32 yParityAndS)
    external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) forTargetChain(encodedSwap)
  {
    require(recipient != address(0), "Recipient cannot be zero address");

    bytes32 digest = keccak256(abi.encodePacked(encodedSwap, recipient));
    _checkSignature(digest, r, yParityAndS, _premiumManager);

    uint256 amount = _amountFrom(encodedSwap);
    uint8 inTokenIndex = _inTokenIndexFrom(encodedSwap);
    uint256 releaseAmount = amount - _feeForLp(encodedSwap);

    _balanceOfPoolToken[_poolTokenIndexFrom(inTokenIndex, 1)] += amount;
    _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 1)] -= releaseAmount;

    _unsafeDepositToken(inTokenIndex, _msgSender(), amount);
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), _msgSender(), recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }
}

File 20 of 28 : IMesonPoolsEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title MesonPools Interface
interface IMesonPoolsEvents {
  /// @notice Event when an LP pool is registered.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param owner Pool owner
  event PoolRegistered(uint40 indexed poolIndex, address owner);

  /// @notice Event when fund was deposited to an LP pool.
  /// Emit at the end of `depositAndRegister()` and `deposit()` calls.
  /// @param poolTokenIndex Concatenation of pool index & token index
  /// @param amount The amount of tokens to be added to the pool
  event PoolDeposited(uint48 indexed poolTokenIndex, uint256 amount);

  /// @notice Event when fund was withdrawn from an LP pool.
  /// Emit at the end of `withdraw()` calls.
  /// @param poolTokenIndex Concatenation of pool index & token index
  /// @param amount The amount of tokens to be removed from the pool
  event PoolWithdrawn(uint48 indexed poolTokenIndex, uint256 amount);

  /// @notice Event when an authorized address was added for an LP pool.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param addr Authorized address to be added
  event PoolAuthorizedAddrAdded(uint40 indexed poolIndex, address addr);

  /// @notice Event when an authorized address was removed for an LP pool.
  /// Emit at the end of `depositAndRegister()` calls.
  /// @param poolIndex Pool index
  /// @param addr Authorized address to be removed
  event PoolAuthorizedAddrRemoved(uint40 indexed poolIndex, address addr);

  /// @notice Event when the ownership of a pool was transferred.
  /// Emit at the end of `transferPoolOwner()` calls.
  /// @param poolIndex Pool index
  /// @param prevOwner Previous owner of the pool
  /// @param newOwner New owner of the pool
  event PoolOwnerTransferred(uint40 indexed poolIndex, address prevOwner, address newOwner);

  /// @notice Event when a swap was locked.
  /// Emit at the end of `lock()` and `lockSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapLocked(uint256 indexed encodedSwap);

  /// @notice Event when a swap was unlocked.
  /// Emit at the end of `unlock()` calls.
  /// @param encodedSwap Encoded swap
  event SwapUnlocked(uint256 indexed encodedSwap);

  /// @notice Event when a swap was released.
  /// Emit at the end of `release()`, `directRelease()` calls.
  /// @param encodedSwap Encoded swap
  event SwapReleased(uint256 indexed encodedSwap);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "./IMesonPoolsEvents.sol";
import "../utils/MesonStates.sol";

/// @title MesonPools
/// @notice The class to manage pools for LPs, and perform swap operations on the target 
/// chain side.
/// Methods in this class will be executed when a user wants to swap into this chain.
/// LP pool operations are also provided in this class.
contract MesonPools is IMesonPoolsEvents, MesonStates {
  /// @notice Locked Swaps
  /// key: `swapId` is calculated from `encodedSwap` and `initiator`. See `_getSwapId` in `MesonHelpers.sol`
  ///   encodedSwap: see `MesonSwap.sol` for defination;
  ///   initiator: The user address who created and signed the swap request.
  /// value: `lockedSwap` in format of `until:uint40|poolIndex:uint40`
  ///   until: The expiration time of this swap on the target chain. Need to `release` the swap fund before `until`;
  ///   poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  mapping(bytes32 => uint80) internal _lockedSwaps;

  /// @dev This empty reserved space is put in place to allow future versions to
  /// add new variables without shifting down storage in the inheritance chain.
  /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  uint256[50] private __gap;

  /// @notice Initially deposit tokens into an LP pool and register a pool index.
  /// This is the prerequisite for LPs if they want to participate in Meson swaps.
  /// @dev Designed to be used by a new address who wants to be an LP and register a pool index
  /// @param amount The amount of tokens to be added to the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function depositAndRegister(uint256 amount, uint48 poolTokenIndex) payable external {
    require(amount > 0, "Amount must be positive");

    address poolOwner = _msgSender();
    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(ownerOfPool[poolIndex] == address(0), "Pool index already registered");
    require(poolOfAuthorizedAddr[poolOwner] == 0, "Signer address already registered");
    ownerOfPool[poolIndex] = poolOwner;
    poolOfAuthorizedAddr[poolOwner] = poolIndex;

    _balanceOfPoolToken[poolTokenIndex] += amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _unsafeDepositToken(tokenIndex, poolOwner, amount);

    emit PoolRegistered(poolIndex, poolOwner);
    emit PoolDeposited(poolTokenIndex, amount);
  }

  /// @notice Deposit tokens into the liquidity pool.
  /// The LP should be careful to make sure the `poolTokenIndex` is correct.
  /// Make sure to call `depositAndRegister` first and register a pool index.
  /// Otherwise, token may be deposited to others.
  /// @dev Designed to be used by addresses authorized to a pool
  /// @param amount The amount of tokens to be added to the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40`. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function deposit(uint256 amount, uint48 poolTokenIndex) payable external {
    require(amount > 0, "Amount must be positive");

    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(poolIndex == poolOfAuthorizedAddr[_msgSender()], "Need an authorized address as the signer");
    _balanceOfPoolToken[poolTokenIndex] += amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _unsafeDepositToken(tokenIndex, _msgSender(), amount);

    emit PoolDeposited(poolTokenIndex, amount);
  }

  /// @notice Withdraw tokens from the liquidity pool.
  /// @dev Designed to be used by LPs (pool owners) who have already registered a pool index
  /// @param amount The amount to be removed from the pool
  /// @param poolTokenIndex In format of `tokenIndex:uint8|poolIndex:uint40. See `_balanceOfPoolToken` in `MesonStates.sol` for more information.
  function withdraw(uint256 amount, uint48 poolTokenIndex) external {
    require(amount > 0, "Amount must be positive");

    uint40 poolIndex = _poolIndexFrom(poolTokenIndex);
    require(poolIndex != 0, "Cannot use 0 as pool index"); // pool 0 is reserved for meson service fee
    require(ownerOfPool[poolIndex] == _msgSender(), "Need the pool owner as the signer");
    _balanceOfPoolToken[poolTokenIndex] -= amount;
    uint8 tokenIndex = _tokenIndexFrom(poolTokenIndex);
    _safeTransfer(tokenIndex, _msgSender(), amount);

    emit PoolWithdrawn(poolTokenIndex, amount);
  }

  /// @notice Add an authorized address to the pool
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The address to be added
  function addAuthorizedAddr(address addr) external {
    require(poolOfAuthorizedAddr[addr] == 0, "Addr is authorized for another pool");
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    poolOfAuthorizedAddr[addr] = poolIndex;

    emit PoolAuthorizedAddrAdded(poolIndex, addr);
  }
  
  /// @notice Remove an authorized address from the pool
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The address to be removed
  function removeAuthorizedAddr(address addr) external {
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
    delete poolOfAuthorizedAddr[addr];

    emit PoolAuthorizedAddrRemoved(poolIndex, addr);
  }

  /// @notice Transfer the ownership of a pool to another address
  /// @dev Designed to be used by LPs (pool owners)
  /// @param addr The new address to be the pool owner
  function transferPoolOwner(address addr) external {
    address poolOwner = _msgSender();
    uint40 poolIndex = poolOfAuthorizedAddr[poolOwner];
    require(poolIndex != 0, "The signer does not register a pool");
    require(poolOwner == ownerOfPool[poolIndex], "Need the pool owner as the signer");
    require(poolOfAuthorizedAddr[addr] == poolIndex, "Addr is not authorized for the signer's pool");
    ownerOfPool[poolIndex] = addr;

    emit PoolOwnerTransferred(poolIndex, poolOwner, addr);
  }

  function lock(uint256 encodedSwap, bytes32 r, bytes32 yParityAndS, address initiator) external {
    // deprecated
    lockSwap(encodedSwap, initiator);
  }

  /// @notice Lock funds to match a swap request. This is step 2️⃣ in a swap.
  /// The authorized address of the bonding pool should call this method,
  /// which will lock swapping fund on the target chain for `LOCK_TIME_PERIOD`
  /// and wait for fund release and execution.
  /// @dev Designed to be used by authorized addresses or pool owners
  /// @param encodedSwap Encoded swap information
  /// @param initiator The swap initiator who created and signed the swap request
  function lockSwap(uint256 encodedSwap, address initiator)
    public matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap)
  {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] == 0, "Swap already exists");

    uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
    require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");

    uint256 until = block.timestamp + LOCK_TIME_PERIOD;
    require(until < _expireTsFrom(encodedSwap) - 5 minutes, "Cannot lock because expireTs is soon.");

    uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
    _balanceOfPoolToken[poolTokenIndex] -= _amountToLock(encodedSwap); // The service fee will be charged on release

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
    }

    _lockedSwaps[swapId] = _lockedSwapFrom(until, poolIndex);

    emit SwapLocked(encodedSwap);
  }

  /// @notice If the locked swap is not released after `LOCK_TIME_PERIOD`,
  /// the authorized address can call this method to unlock the swapping fund.
  /// @dev Designed to be used by authorized addresses or pool owners
  /// @param encodedSwap Encoded swap information
  /// @param initiator The swap initiator who created and signed the swap request
  function unlock(uint256 encodedSwap, address initiator) external {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    uint80 lockedSwap = _lockedSwaps[swapId];
    require(lockedSwap > 1, "Swap does not exist");
    require(_untilFromLocked(lockedSwap) < block.timestamp, "Swap still in lock");

    uint40 poolIndex = _poolIndexFromLocked(lockedSwap);
    uint48 poolTokenIndex = _poolTokenIndexForOutToken(encodedSwap, poolIndex);
    _balanceOfPoolToken[poolTokenIndex] += _amountToLock(encodedSwap);

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] += coreAmount;
    }

    delete _lockedSwaps[swapId];

    emit SwapUnlocked(encodedSwap);
  }

  /// @notice Release tokens to satisfy a locked swap. This is step 3️⃣ in a swap.
  /// This method requires a release signature from the swap initiator,
  /// but anyone (initiator herself, the LP, and other people) with the signature 
  /// can call this method to make sure the swapping fund is guaranteed to be released.
  /// @dev Designed to be used by anyone
  /// @param encodedSwap Encoded swap information
  /// @param r Part of the release signature (same as in the `executeSwap` call)
  /// @param yParityAndS Part of the release signature (same as in the `executeSwap` call)
  /// @param initiator The swap initiator who created and signed the swap request
  /// @param recipient The recipient address of the swap
  function release(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) external {
    require(_msgSender() == tx.origin, "Cannot be called through contracts");
    require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
    require(recipient != address(0), "Recipient cannot be zero address");

    bool feeWaived = _feeWaived(encodedSwap);
    if (feeWaived) {
      // For swaps that service fee is waived, need the premium manager as the signer
      require(_isPremiumManager(), "Caller is not the premium manager");
    }
    // For swaps that charge service fee, anyone can call

    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] > 1, "Swap does not exist");

    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
    _lockedSwaps[swapId] = 1;

    // LP fee will be subtracted from the swap amount
    uint256 releaseAmount = _amountToLock(encodedSwap);
    if (!feeWaived) { // If the swap should pay service fee (charged by Meson protocol)
      uint256 serviceFee = _serviceFee(encodedSwap);
      // Subtract service fee from the release amount
      releaseAmount -= serviceFee;
      // Collected service fee will be stored in `_balanceOfPoolToken` with `poolIndex = 0`.
      // Currently, no one is capable to withdraw fund from pool 0. In the future, Meson protocol
      // will specify the purpose of service fee and its usage permission, and upgrade the contract
      // accordingly.
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
    }

    uint256 amountToShare = _amountToShare(encodedSwap);
    if (amountToShare > 0) {
      releaseAmount -= amountToShare;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
    }

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _transferCoreToken(recipient, coreAmount);
    }
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }

  function directRelease(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) external matchProtocolVersion(encodedSwap) forTargetChain(encodedSwap) {
    require(_msgSender() == tx.origin, "Cannot be called through contracts");
    require(recipient != address(0), "Recipient cannot be zero address");

    bool feeWaived = _feeWaived(encodedSwap);
    if (feeWaived) {
      require(_isPremiumManager(), "Caller is not the premium manager");
    }

    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    require(_lockedSwaps[swapId] == 0, "Swap already exists");

    uint40 poolIndex = poolOfAuthorizedAddr[_msgSender()];
    require(poolIndex != 0, "Caller not registered. Call depositAndRegister.");

    if (r != bytes32(0x0)) {
      require(_expireTsFrom(encodedSwap) > block.timestamp, "Cannot release because expired");
      _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);
    } else if (!feeWaived) {
      require(_isPremiumManager(), "Caller is not the premium manager");
    }
    _lockedSwaps[swapId] = 1;

    uint256 releaseAmount = _amountToLock(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, poolIndex)] -= releaseAmount;

    if (!feeWaived) {
      uint256 serviceFee = _serviceFee(encodedSwap);
      releaseAmount -= serviceFee;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, 0)] += serviceFee;
    }

    uint256 amountToShare = _amountToShare(encodedSwap);
    if (amountToShare > 0) {
      releaseAmount -= amountToShare;
      _balanceOfPoolToken[_poolTokenIndexForOutToken(encodedSwap, _poolIndexToShare(encodedSwap))] += amountToShare;
    }

    uint256 coreAmount = _coreTokenAmount(encodedSwap);
    if (coreAmount > 0) {
      _balanceOfPoolToken[_poolTokenIndexFrom(indexOfToken[address(1)], poolIndex)] -= coreAmount;
      _transferCoreToken(recipient, coreAmount);
    }
    _release(encodedSwap, _outTokenIndexFrom(encodedSwap), initiator, recipient, releaseAmount);

    emit SwapReleased(encodedSwap);
  }

  function _release(uint256 encodedSwap, uint8 tokenIndex, address initiator, address recipient, uint256 amount) internal {
    if (_willTransferToContract(encodedSwap)) {
      _transferToContract(tokenIndex, recipient, initiator, amount, _saltDataFrom(encodedSwap));
    } else if (amount > 0) {
      _safeTransfer(tokenIndex, recipient, amount);
      if ((SHORT_COIN_TYPE == 0x9296 || SHORT_COIN_TYPE == 0xb4b1 || SHORT_COIN_TYPE == 0x6c62) && _swapForCoreToken(encodedSwap)) {
        _callSkaleFaucet(recipient);
      }
    }
  }

  function _callSkaleFaucet(address recipient) private {
    if (SHORT_COIN_TYPE == 0x9296) {
      // SKALE Europa
      bytes memory data = abi.encodeWithSelector(bytes4(0x6a627842), recipient);
      (bool success, ) = address(0x2B267A3e49b351DEdac892400a530ABb2f899d23).call(data);
      require(success, "Call faucet not successful");
    } else if (SHORT_COIN_TYPE == 0xb4b1) {
      // SKALE Nebula
      bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
      (bool success, ) = address(0x5a6869ef5b81DCb58EBF51b8F893c31f5AFE3Fa8).call(data);
      require(success, "Call faucet not successful");
    } else if (SHORT_COIN_TYPE == 0x6c62) {
      // SKALE Calypso
      bytes memory data = abi.encodeWithSelector(bytes4(0x0c11dedd), recipient);
      (bool success, ) = address(0x02891b34B7911A9C68e82C193cd7A6fBf0c3b30A).call(data);
      require(success, "Call faucet not successful");
    }
  }

  /// @notice Read information for a locked swap
  function getLockedSwap(uint256 encodedSwap, address initiator) external view
    returns (address poolOwner, uint40 until)
  {
    bytes32 swapId = _getSwapId(encodedSwap, initiator);
    uint80 lockedSwap = _lockedSwaps[swapId];
    if (lockedSwap == 1) {
      poolOwner = address(1);
      until = 0;
    } else {
      poolOwner = ownerOfPool[_poolIndexFromLocked(lockedSwap)];
      until = uint40(_untilFromLocked(lockedSwap));
    }
  }

  modifier forTargetChain(uint256 encodedSwap) {
    require(_outChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
    _;
  }

  function _isPremiumManager() internal view virtual returns (bool) {}
}

File 22 of 28 : IMesonSwapEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title MesonSwapEvents Interface
interface IMesonSwapEvents {
  /// @notice Event when a swap request was posted.
  /// Emit at the end of `postSwap()`, `postSwapFromInitiator()` and `postSwapFromContract()` calls.
  /// @param encodedSwap Encoded swap
  event SwapPosted(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was bonded.
  /// Emit at the end of `bondSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapBonded(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was cancelled.
  /// Emit at the end of `cancelSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapCancelled(uint256 indexed encodedSwap);

  /// @notice Event when a swap request was executed.
  /// Emit at the end of `executeSwap()`, `directExecuteSwap()` and `simpleExecuteSwap()` calls.
  /// @param encodedSwap Encoded swap
  event SwapExecuted(uint256 indexed encodedSwap);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "./IMesonSwapEvents.sol";
import "../utils/MesonStates.sol";

/// @title MesonSwap
/// @notice The class to receive and process swap requests on the initial chain side.
/// Methods in this class will be executed by swap initiators or LPs
/// on the initial chain of swaps.
contract MesonSwap is IMesonSwapEvents, MesonStates {
  /// @notice Posted Swaps
  /// key: `encodedSwap` in format of `version:uint8|amount:uint40|salt:uint80|fee:uint40|expireTs:uint40|outChain:uint16|outToken:uint8|inChain:uint16|inToken:uint8`
  ///   version: Version of encoding
  ///   amount: The amount of tokens of this swap, always in decimal 6. The amount of a swap is capped at $100k so it can be safely encoded in uint48;
  ///   salt: The salt value of this swap, carrying some information below:
  ///     salt & 0x80000000000000000000 == true => will release to an EOA address, otherwise a smart contract;
  ///     salt & 0x40000000000000000000 == true => will waive *service fee*;
  ///     salt & 0x20000000000000000000 == true => meson.to;
  ///     salt & 0x10000000000000000000 == true => API;
  ///     salt & 0x08000000000000000000 == true => use *non-typed signing* (some wallets such as hardware wallets don't support EIP-712v1);
  ///     salt & 0x04000000000000000000 == true => swap for core token (n/a for releasing to contract);
  ///         salt & 0xfffff00000000000         => price for core token;
  ///         salt & 0x00000fff00000000         => amount for core token;
  ///     salt & 0x02000000000000000000 == true => share some release amount to partner;
  ///         salt & 0xffff000000000000 + 65536 => pool index to share;
  ///         salt & 0x0000ffff00000000         => amount to share;
  ///     salt & 0x01000000000000000000 == true => use points to waive service fee;
  ///                                              in reality, the salt header would be 0x41
  ///     salt & 0x0000ffffffffffffffff: customized data that can be passed to integrated 3rd-party smart contract;
  ///   fee: The fee given to LPs (liquidity providers). An extra service fee maybe charged afterwards;
  ///   expireTs: The expiration time of this swap on the initial chain. The LP should `executeSwap` and receive his funds before `expireTs`;
  ///   outChain: The target chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
  ///   outToken: The index of the token on the target chain. See `tokenForIndex` in `MesonToken.sol`;
  ///   inChain: The initial chain of a cross-chain swap (given by the last 2 bytes of SLIP-44);
  ///   inToken: The index of the token on the initial chain. See `tokenForIndex` in `MesonToken.sol`.
  /// value: `postedSwap` in format of `initiator:address|poolIndex:uint40`
  ///   initiator: The swap initiator who created and signed the swap request (not necessarily the one who posted the swap);
  //    poolIndex: The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  mapping(uint256 => uint200) internal _postedSwaps;

  /// @dev This empty reserved space is put in place to allow future versions to
  /// add new variables without shifting down storage in the inheritance chain.
  /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  uint256[50] private __gap;

  /// @notice Anyone can call this method to post a swap request. This is step 1️⃣ in a swap.
  /// The r,s,v signature must be signed by the swap initiator. The initiator can call
  /// this method directly, in which case `poolIndex` should be zero and wait for LPs
  /// to call `bondSwap`. Initiators can also send the swap requests offchain (through the
  /// meson relayer service). An LP (pool owner or authorized addresses) who receives requests through
  /// the relayer can call this method to post and bond the swap in a single contract execution,
  /// in which case he should give his own `poolIndex`.
  ///
  /// The swap will last until `expireTs` and at most one LP pool can bond to it.
  /// After the swap expires, the initiator can cancel the swap and withdraw funds.
  ///
  /// Once a swap is posted and bonded, the bonding LP should call `lock` on the target chain.
  ///
  /// @dev Designed to be used by both swap initiators, pool owner, or authorized addresses
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param postingValue The value to be written to `_postedSwaps`. See `_postedSwaps` for encoding format
  function postSwap(uint256 encodedSwap, bytes32 r, bytes32 yParityAndS, uint200 postingValue)
    external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    address initiator = _initiatorFromPosted(postingValue);
    uint40 poolIndex = _poolIndexFromPosted(postingValue);
    if (poolIndex > 0 && _msgSender() != initiator) {
      // If pool index is given, the signer should be the initiator or an authorized address
      require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");
    } // Otherwise, this is posted without bonding to a specific pool. Need to execute `bondSwap` later

    _checkRequestSignature(encodedSwap, r, yParityAndS, initiator);
    _postedSwaps[encodedSwap] = postingValue;

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _unsafeDepositToken(tokenIndex, initiator, _amountFrom(encodedSwap));

    emit SwapPosted(encodedSwap);
  }

  function postSwapFromInitiator(uint256 encodedSwap, uint200 postingValue)
    payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    address initiator = _initiatorFromPosted(postingValue);
    require(_msgSender() == initiator, "Transaction should be sent from initiator");
    _postedSwaps[encodedSwap] = postingValue;

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _unsafeDepositToken(tokenIndex, initiator, _amountFrom(encodedSwap));

    emit SwapPosted(encodedSwap);
  }

  function postSwapFromContract(uint256 encodedSwap, uint200 postingValue, address contractAddress)
    payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    address initiator = _initiatorFromPosted(postingValue);
    require(_msgSender() == contractAddress, "Transaction should be sent from contractAddress");
    _postedSwaps[encodedSwap] = postingValue;

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _unsafeDepositToken(tokenIndex, contractAddress, _amountFrom(encodedSwap));

    emit SwapPosted(encodedSwap);
  }

  /// @notice If `postSwap` is called by the initiator of the swap and `poolIndex`
  /// is zero, an LP (pool owner or authorized addresses) can call this to bond the swap to himself.
  /// @dev Designed to be used by pool owner or authorized addresses
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param poolIndex The index of an LP pool. See `ownerOfPool` in `MesonStates.sol` for more information.
  function bondSwap(uint256 encodedSwap, uint40 poolIndex) external {
    uint200 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_poolIndexFromPosted(postedSwap) == 0, "Swap bonded to another pool");
    require(poolOfAuthorizedAddr[_msgSender()] == poolIndex, "Signer should be an authorized address of the given pool");

    _postedSwaps[encodedSwap] = postedSwap | poolIndex;
    emit SwapBonded(encodedSwap);
  }

  /// @notice Cancel a swap. The swap initiator can call this method to withdraw funds
  /// from an expired swap request.
  /// @dev Designed to be used by swap initiators
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  function cancelSwap(uint256 encodedSwap) external {
    uint200 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");

    delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _safeTransfer(tokenIndex, _initiatorFromPosted(postedSwap), _amountFrom(encodedSwap));

    emit SwapCancelled(encodedSwap);
  }

  function cancelSwapTo(uint256 encodedSwap, address recipient, bytes32 r, bytes32 yParityAndS) external {
    uint200 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");
    require(_expireTsFrom(encodedSwap) < block.timestamp, "Swap is still locked");

    bytes32 digest = keccak256(abi.encodePacked(encodedSwap, recipient));
    _checkSignature(digest, r, yParityAndS, _initiatorFromPosted(postedSwap));

    delete _postedSwaps[encodedSwap]; // Swap expired so the same one cannot be posted again

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _safeTransfer(tokenIndex, recipient, _amountFrom(encodedSwap));

    emit SwapCancelled(encodedSwap);
  }

  /// @notice Execute the swap by providing a release signature. This is step 4️⃣ in a swap.
  /// Once the signature is verified, the current bonding pool will receive funds deposited 
  /// by the swap initiator.
  /// @dev Designed to be used by pool owner or authorized addresses of the current bonding pool
  /// @param encodedSwap Encoded swap information; also used as the key of `_postedSwaps`
  /// @param r Part of the release signature (same as in the `release` call)
  /// @param yParityAndS Part of the release signature (same as in the `release` call)
  /// @param recipient The recipient address of the swap
  /// @param depositToPool Whether to deposit funds to the pool (will save gas)
  function executeSwap(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address recipient,
    bool depositToPool
  ) external {
    uint200 postedSwap = _postedSwaps[encodedSwap];
    require(postedSwap > 1, "Swap does not exist");

    // Swap expiredTs < current + MIN_BOND_TIME_PERIOD
    if (_expireTsFrom(encodedSwap) < block.timestamp + MIN_BOND_TIME_PERIOD) {
      // The swap cannot be posted again and therefore safe to remove it.
      // LPs who execute in this mode can save ~5000 gas.
      delete _postedSwaps[encodedSwap];
    } else {
      // The same swap information can be posted again, so set `_postedSwaps` value to 1 to prevent that.
      _postedSwaps[encodedSwap] = 1;
    }

    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, _initiatorFromPosted(postedSwap));

    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    uint40 poolIndex = _poolIndexFromPosted(postedSwap);
    if (depositToPool) {
      _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)] += _amountFrom(encodedSwap);
    } else {
      _safeTransfer(tokenIndex, ownerOfPool[poolIndex], _amountFrom(encodedSwap));
    }

    emit SwapExecuted(encodedSwap);
  }

  function directExecuteSwap(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address initiator,
    address recipient
  ) payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap) {
    _checkReleaseSignature(encodedSwap, recipient, r, yParityAndS, initiator);

    _postedSwaps[encodedSwap] = 1;

    uint256 amount = _amountFrom(encodedSwap);
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;

    _unsafeDepositToken(tokenIndex, initiator, amount);

    emit SwapExecuted(encodedSwap);
  }

  function simpleExecuteSwap(uint256 encodedSwap)
    payable external matchProtocolVersion(encodedSwap) verifyEncodedSwap(encodedSwap)
  {
    uint256 amount = _amountFrom(encodedSwap);
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 1)] += amount;

    _unsafeDepositToken(tokenIndex, _msgSender(), amount);

    emit SwapExecuted(encodedSwap);
  }

  /// @notice Read information for a posted swap
  function getPostedSwap(uint256 encodedSwap) external view
    returns (address initiator, address poolOwner, bool exist)
  {
    uint200 postedSwap = _postedSwaps[encodedSwap];
    initiator = _initiatorFromPosted(postedSwap);
    exist = postedSwap > 0;
    if (initiator == address(0)) {
      poolOwner = address(0);
    } else {
      poolOwner = ownerOfPool[_poolIndexFromPosted(postedSwap)];
    }
  }

  modifier verifyEncodedSwap(uint256 encodedSwap) {
    require(_inChainFrom(encodedSwap) == SHORT_COIN_TYPE, "Swap not for this chain");
    require(
      _tokenType(_inTokenIndexFrom(encodedSwap)) == _tokenType(_outTokenIndexFrom(encodedSwap)),
      "In & out token types do not match"
    );
    require(_postedSwaps[encodedSwap] == 0, "Swap already exists");

    require(_amountFrom(encodedSwap) <= MAX_SWAP_AMOUNT, "For security reason, amount cannot be greater than 100k");

    uint256 delta = _expireTsFrom(encodedSwap) - block.timestamp;
    require(delta > MIN_BOND_TIME_PERIOD, "Expire ts too early");
    require(delta < MAX_BOND_TIME_PERIOD, "Expire ts too late");

    _;
  }

  function _isPremiumManager() internal view virtual returns (bool) {}
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "./MesonManager.sol";

contract UpgradableMeson is UUPSUpgradeable, MesonManager {
  function initialize(address owner, address premiumManager) external initializer {
    _transferOwnership(owner);
    _transferPremiumManager(premiumManager);
  }

  function _authorizeUpgrade(address) internal override onlyOwner {}
}

File 25 of 28 : MesonConfig.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @notice Parameters of the Meson contract
/// for MemeCore
contract MesonConfig {
  uint8 constant MESON_PROTOCOL_VERSION = 1;

  // Ref https://github.com/satoshilabs/slips/blob/master/slip-0044.md
  uint16 constant SHORT_COIN_TYPE = 0x1100;

  uint256 constant MAX_SWAP_AMOUNT = 1e11; // 100,000.000000 = 100k
  uint256 constant SERVICE_FEE_RATE = 5; // service fee = 5 / 10000 = 0.05%
  uint256 constant SERVICE_FEE_MINIMUM = 500_000; // min $0.5
  uint256 constant SERVICE_FEE_MINIMUM_ETH = 500; // min 0.0005 ETH (or SOL)
  uint256 constant SERVICE_FEE_MINIMUM_BNB = 5000; // min 0.005 BNB
  uint256 constant SERVICE_FEE_MINIMUM_BTC = 10; // min 0.00001 BTC

  uint256 constant MIN_BOND_TIME_PERIOD = 1 hours;
  uint256 constant MAX_BOND_TIME_PERIOD = 2 hours;
  uint256 constant LOCK_TIME_PERIOD = 20 minutes;

  bytes28 constant ETH_SIGN_HEADER = bytes28("\x19Ethereum Signed Message:\n32");
  bytes28 constant ETH_SIGN_HEADER_52 = bytes28("\x19Ethereum Signed Message:\n52");
  bytes25 constant TRON_SIGN_HEADER = bytes25("\x19TRON Signed Message:\n32\n");
  bytes25 constant TRON_SIGN_HEADER_33 = bytes25("\x19TRON Signed Message:\n33\n");
  bytes25 constant TRON_SIGN_HEADER_53 = bytes25("\x19TRON Signed Message:\n53\n");

  bytes32 constant REQUEST_TYPE_HASH = keccak256("bytes32 Sign to request a swap on Meson");
  bytes32 constant RELEASE_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient");

  bytes32 constant RELEASE_TO_TRON_TYPE_HASH = keccak256("bytes32 Sign to release a swap on Mesonaddress Recipient (tron address in hex format)");
}

File 26 of 28 : MesonHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts/utils/Context.sol";
import "./MesonConfig.sol";

/// @title MesonHelpers
/// @notice The class that provides helper functions for Meson protocol
contract MesonHelpers is MesonConfig, Context {
  modifier matchProtocolVersion(uint256 encodedSwap) {
    require(_versionFrom(encodedSwap) == MESON_PROTOCOL_VERSION, "Incorrect encoding version");
    _;
  }

  function getShortCoinType() external pure returns (bytes2) {
    return bytes2(SHORT_COIN_TYPE);
  }

  /// @notice Calculate `swapId` from `encodedSwap`, `initiator`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _getSwapId(uint256 encodedSwap, address initiator) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked(encodedSwap, initiator));
  }

  /// @notice Decode `version` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _versionFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap >> 248);
  }

  /// @notice Decode `amount` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _amountFrom(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 208) & 0xFFFFFFFFFF;
  }

  function _amountToLock(uint256 encodedSwap) internal pure returns (uint256) {
    return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - _amountForCoreTokenFrom(encodedSwap);
  }

  /// @notice Calculate the service fee from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _serviceFee(uint256 encodedSwap) internal pure returns (uint256) {
    uint8 tokenIndex = _inTokenIndexFrom(encodedSwap);
    uint256 minFee;
    if (tokenIndex >= 252) {
      minFee = SERVICE_FEE_MINIMUM_ETH;
    } else if (tokenIndex >= 248) {
      minFee = SERVICE_FEE_MINIMUM_BNB;
    } else if (tokenIndex >= 244) {
      minFee = SERVICE_FEE_MINIMUM_ETH;
    } else if (tokenIndex >= 240) {
      minFee = SERVICE_FEE_MINIMUM_BTC;
    } else {
      minFee = SERVICE_FEE_MINIMUM;
    }
    // Default to `serviceFee` = 0.05% * `amount`
    uint256 fee = _amountFrom(encodedSwap) * SERVICE_FEE_RATE / 10000;
    return fee > minFee ? fee : minFee;
  }

  /// @notice Decode `fee` (the fee for LPs) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _feeForLp(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 88) & 0xFFFFFFFFFF;
  }

  /// @notice Decode `salt` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _saltFrom(uint256 encodedSwap) internal pure returns (uint80) {
    return uint80(encodedSwap >> 128);
  }

  /// @notice Decode data from `salt`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _saltDataFrom(uint256 encodedSwap) internal pure returns (uint64) {
    return uint64(encodedSwap >> 128);
  }

  /// @notice Whether the swap should release to a 3rd-party integrated dapp contract
  /// See method `release` in `MesonPools.sol` for more details
  function _willTransferToContract(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x8000000000000000000000000000000000000000000000000000) == 0;
  }

  /// @notice Whether the swap needs to pay service fee
  /// See method `release` in `MesonPools.sol` for more details about the service fee
  function _feeWaived(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x4000000000000000000000000000000000000000000000000000) > 0;
  }
  
  /// @notice Whether the swap was signed in the non-typed manner (usually by hardware wallets)
  function _signNonTyped(uint256 encodedSwap) internal pure returns (bool) {
    return (encodedSwap & 0x0800000000000000000000000000000000000000000000000000) > 0;
  }

  function _swapForCoreToken(uint256 encodedSwap) internal pure returns (bool) {
    return (_outTokenIndexFrom(encodedSwap) < 191) &&
      ((encodedSwap & 0x8410000000000000000000000000000000000000000000000000) == 0x8410000000000000000000000000000000000000000000000000);
  }

  function _amountForCoreTokenFrom(uint256 encodedSwap) internal pure returns (uint256) {
    if (_swapForCoreToken(encodedSwap)) {
      uint256 d = (encodedSwap >> 160) & 0xFFFF;
      if (d == 0xFFFF) {
        return _amountFrom(encodedSwap) - _feeForLp(encodedSwap) - (_feeWaived(encodedSwap) ? 0 : _serviceFee(encodedSwap));
      }
      return _decompressFixedPrecision(d) * 1e3;
    }
    return 0;
  }

  function _coreTokenAmount(uint256 encodedSwap) internal pure returns (uint256) {
    uint256 amountForCore = _amountForCoreTokenFrom(encodedSwap);
    if (amountForCore > 0) {
      return amountForCore * 1e4 / _decompressFixedPrecision((encodedSwap >> 176) & 0xFFFF);
    }
    return 0;
  }

  function _shareWithPartner(uint256 encodedSwap) internal pure returns (bool) {
    return !_willTransferToContract(encodedSwap)
      && ((encodedSwap & 0x0600000000000000000000000000000000000000000000000000) == 0x0200000000000000000000000000000000000000000000000000);
  }

  function _amountToShare(uint256 encodedSwap) internal pure returns (uint256) {
    if (_shareWithPartner(encodedSwap)) {
      return _decompressFixedPrecision((encodedSwap >> 160) & 0xFFFF);
    }
    return 0;
  }

  function _decompressFixedPrecision(uint256 d) internal pure returns (uint256) {
    if (d <= 1000) {
      return d;
    }
    return ((d - 1000) % 9000 + 1000) * 10 ** ((d - 1000) / 9000);
  }

  function _poolIndexToShare(uint256 encodedSwap) internal pure returns (uint40) {
    if (_shareWithPartner(encodedSwap)) {
      return (uint40(encodedSwap >> 176) & 0xFFFF) + 65536;
    }
    return 0;
  }

  /// @notice Decode `expireTs` from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _expireTsFrom(uint256 encodedSwap) internal pure returns (uint256) {
    return (encodedSwap >> 48) & 0xFFFFFFFFFF;
    // [Suggestion]: return uint40(encodedSwap >> 48);
  }

  /// @notice Decode the initial chain (`inChain`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _inChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
    return uint16(encodedSwap >> 8);
  }

  /// @notice Decode the token index of initial chain (`inToken`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _inTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap);
  }

  /// @notice Decode the target chain (`outChain`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _outChainFrom(uint256 encodedSwap) internal pure returns (uint16) {
    return uint16(encodedSwap >> 32);
  }

  /// @notice Decode the token index of target chain (`outToken`) from `encodedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  function _outTokenIndexFrom(uint256 encodedSwap) internal pure returns (uint8) {
    return uint8(encodedSwap >> 24);
  }

  function _tokenType(uint8 tokenIndex) internal pure returns (uint8) {
    if (tokenIndex >= 192) {
      // Non stablecoins [192, 255] -> [48, 63]
      return tokenIndex / 4;
    } else if (tokenIndex <= 64) {
      // Stablecoins [1, 64] -> 0
      return 0;
    } else if (tokenIndex <= 112) {
      // 3rd party tokens [65, 112] -> [1, 24]
      return (tokenIndex + 1) / 2 - 32;
    } else if (tokenIndex <= 128) {
      // 3rd party tokens [113, 128] -> [33, 48]
      return tokenIndex - 80;
    }
    revert("Token index not allowed for swapping");
  }

  /// @notice Decode `outToken` from `encodedSwap`, and encode it with `poolIndex` to `poolTokenIndex`.
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolTokenIndexForOutToken(uint256 encodedSwap, uint40 poolIndex) internal pure returns (uint48) {
    return uint48((encodedSwap & 0xFF000000) << 16) | poolIndex;
  }

  /// @notice Decode `initiator` from `postedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
  function _initiatorFromPosted(uint200 postedSwap) internal pure returns (address) {
    return address(uint160(postedSwap >> 40));
  }

  /// @notice Decode `poolIndex` from `postedSwap`
  /// See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `postedSwap`
  function _poolIndexFromPosted(uint200 postedSwap) internal pure returns (uint40) {
    return uint40(postedSwap);
  }
  
  /// @notice Encode `lockedSwap` from `until` and `poolIndex`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _lockedSwapFrom(uint256 until, uint40 poolIndex) internal pure returns (uint80) {
    return (uint80(until) << 40) | poolIndex;
  }

  /// @notice Decode `poolIndex` from `lockedSwap`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _poolIndexFromLocked(uint80 lockedSwap) internal pure returns (uint40) {
    return uint40(lockedSwap);
  }

  /// @notice Decode `until` from `lockedSwap`
  /// See variable `_lockedSwaps` in `MesonPools.sol` for the defination of `lockedSwap`
  function _untilFromLocked(uint80 lockedSwap) internal pure returns (uint256) {
    return uint256(lockedSwap >> 40);
  }

  /// @notice Encode `poolTokenIndex` from `tokenIndex` and `poolIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolTokenIndexFrom(uint8 tokenIndex, uint40 poolIndex) internal pure returns (uint48) {
    return (uint48(tokenIndex) << 40) | poolIndex;
  }

  /// @notice Decode `tokenIndex` from `poolTokenIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _tokenIndexFrom(uint48 poolTokenIndex) internal pure returns (uint8) {
    return uint8(poolTokenIndex >> 40);
  }

  /// @notice Decode `poolIndex` from `poolTokenIndex`
  /// See variable `_balanceOfPoolToken` in `MesonStates.sol` for the defination of `poolTokenIndex`
  function _poolIndexFrom(uint48 poolTokenIndex) internal pure returns (uint40) {
    return uint40(poolTokenIndex);
  }

  /// @notice Check the initiator's signature for a swap request
  /// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and 
  /// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRequest`
  /// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param signer The signer for the swap request which is the `initiator`
  function _checkRequestSignature(
    uint256 encodedSwap,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    bool nonTyped = _signNonTyped(encodedSwap);
    bytes32 digest;
    if (_inChainFrom(encodedSwap) == 0x00c3) {
      digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_33 : TRON_SIGN_HEADER, encodedSwap));
    } else if (nonTyped) {
      digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER, encodedSwap));
    } else {
      bytes32 typehash = REQUEST_TYPE_HASH;
      assembly {
        mstore(0, encodedSwap)
        mstore(32, keccak256(0, 32))
        mstore(0, typehash)
        digest := keccak256(0, 64)
      }
    }
    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }

  /// @notice Check the initiator's signature for the release request
  /// Signatures are constructed with the package `mesonfi/sdk`. Go to `packages/sdk/src/SwapSigner.ts` and 
  /// see how to generate a signautre in class `EthersWalletSwapSigner` method `signSwapRelease`
  /// @param encodedSwap Encoded swap information. See variable `_postedSwaps` in `MesonSwap.sol` for the defination of `encodedSwap`
  /// @param recipient The recipient address of the swap
  /// @param r Part of the signature
  /// @param yParityAndS Part of the signature
  /// @param signer The signer for the swap request which is the `initiator`
  function _checkReleaseSignature(
    uint256 encodedSwap,
    address recipient,
    bytes32 r,
    bytes32 yParityAndS,
    address signer
  ) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    bool nonTyped = _signNonTyped(encodedSwap);
    bytes32 digest;
    if (_inChainFrom(encodedSwap) == 0x00c3) {
      digest = keccak256(abi.encodePacked(nonTyped ? TRON_SIGN_HEADER_53 : TRON_SIGN_HEADER, encodedSwap, recipient));
    } else if (nonTyped) {
      digest = keccak256(abi.encodePacked(ETH_SIGN_HEADER_52, encodedSwap, recipient));
    } else {
      bytes32 typehash = _outChainFrom(encodedSwap) == 0x00c3 ? RELEASE_TO_TRON_TYPE_HASH : RELEASE_TYPE_HASH;
      assembly {
        mstore(20, recipient)
        mstore(0, encodedSwap)
        mstore(32, keccak256(0, 52))
        mstore(0, typehash)
        digest := keccak256(0, 64)
      }
    }
    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }

  function _checkSignature(bytes32 digest, bytes32 r, bytes32 yParityAndS, address signer) internal pure {
    require(signer != address(0), "Signer cannot be empty address");
    bytes32 s = yParityAndS & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    uint8 v = uint8((uint256(yParityAndS) >> 255) + 27);
    require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature");

    require(signer == ecrecover(digest, v, r, s), "Invalid signature");
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts/utils/Address.sol";
import "../interfaces/IERC20Minimal.sol";
import "../interfaces/IDepositWithBeneficiary.sol";
import "./MesonTokens.sol";
import "./MesonHelpers.sol";

/// @title MesonStates
/// @notice The class that keeps track of LP pool states
contract MesonStates is MesonTokens, MesonHelpers {
  bytes4 private constant ERC20_TRANSFER_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
  bytes4 private constant ERC20_TRANSFER_FROM_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));

  /// @notice The mapping from *authorized addresses* to LP pool indexes.
  /// See `ownerOfPool` to understand how pool index is defined and used.
  ///
  /// This mapping records the relation between *authorized addresses* and pool indexes, where
  /// authorized addresses are those who have the permision to match and complete a swap with funds 
  /// in a pool with specific index. For example, for an LP pool with index `i` there could be multiple
  /// addresses that `poolOfAuthorizedAddr[address] = i`, which means these addresses can all sign to match
  /// (call `bondSwap`, `lock`) a swap and complete it (call `release`) with funds in pool `i`. That helps
  /// an LP to give other addresses the permission to perform daily swap transactions. However, authorized
  /// addresses cannot withdraw funds from the LP pool, unless it's given in `ownerOfPool` which records
  /// the *owner* address for each pool.
  ///
  /// The pool index 0 is reserved for use by Meson
  mapping(address => uint40) public poolOfAuthorizedAddr;

  /// @notice The mapping from LP pool indexes to their owner addresses.
  /// Each LP pool in Meson has a uint40 index `i` and each LP needs to register an pool index at
  /// initial deposit by calling `depositAndRegister`. The balance for each LP pool is tracked by its
  /// pool index and token index (see `_balanceOfPoolToken`).
  /// 
  /// This mapping records the *owner* address for each LP pool. Only the owner address can withdraw funds
  /// from its corresponding LP pool.
  ///
  /// The pool index 0 is reserved for use by Meson
  mapping(uint40 => address) public ownerOfPool;

  /// @notice Balance for each token in LP pool, tracked by the `poolTokenIndex`.
  /// See `ownerOfPool` to understand how pool index is defined and used.
  ///
  /// The balance of a token in an LP pool is `_balanceOfPoolToken[poolTokenIndex]` in which
  /// the `poolTokenIndex` is in format of `tokenIndex:uint8|poolIndex:uint40`. `tokenIndex`
  /// is the index of supported tokens given by `tokenForIndex` (see definition in `MesonTokens.sol`).
  /// The balances are always store as tokens have decimal 6, which is the case for USDC/USDT on most chains
  /// except BNB Smart Chain & Conflux. In the exceptional cases, the value of token amount will be converted
  /// on deposit and withdrawal (see `_safeTransfer` and `_unsafeDepositToken` in `MesonHelpers.sol`).
  ///
  /// The pool index 0 is reserved for use by Meson to store service fees
  mapping(uint48 => uint256) internal _balanceOfPoolToken;

  /// @dev This empty reserved space is put in place to allow future versions to
  /// add new variables without shifting down storage in the inheritance chain.
  /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  uint256[50] private __gap;

  function poolTokenBalance(address token, address addr) external view returns (uint256) {
    uint8 tokenIndex = indexOfToken[token];
    uint40 poolIndex = poolOfAuthorizedAddr[addr];
    if (poolIndex == 0 || tokenIndex == 0) {
      return 0;
    }
    return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, poolIndex)];
  }
  
  /// @notice The collected service fee of a specific token.
  /// @param tokenIndex The index of a supported token. See `tokenForIndex` in `MesonTokens.sol`
  function serviceFeeCollected(uint8 tokenIndex) external view returns (uint256) {
    return _balanceOfPoolToken[_poolTokenIndexFrom(tokenIndex, 0)];
  }

  /// @notice Help the senders to transfer their assets to the Meson contract
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param sender The sender of the transfer
  /// @param amount The value of the transfer (always in decimal 6)
  function _unsafeDepositToken(
    uint8 tokenIndex,
    address sender,
    uint256 amount
  ) internal {
    require(amount > 0, "Amount must be greater than zero");

    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      require(amount * 1e12 == msg.value, "msg.value does not match the amount");
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];

      require(token != address(0), "Token not supported");
      require(Address.isContract(token), "The given token address is not a contract");

      amount *= _amountFactor(tokenIndex);
      (bool success, bytes memory data) = token.call(abi.encodeWithSelector(
        ERC20_TRANSFER_FROM_SELECTOR,
        sender,
        address(this),
        amount
      ));
      require(success && (data.length == 0 || abi.decode(data, (bool))), "transferFrom failed");
    }
  }

  /// @notice Safe transfers tokens from Meson contract to a recipient
  /// for interacting with ERC20 tokens that do not consistently return true/false
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param recipient The recipient of the transfer
  /// @param amount The value of the transfer (always in decimal 6)
  function _safeTransfer(
    uint8 tokenIndex,
    address recipient,
    uint256 amount
  ) internal {
    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      _transferCoreToken(recipient, amount);
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];

      require(Address.isContract(token), "The given token address is not a contract");

      amount *= _amountFactor(tokenIndex);
      if (SHORT_COIN_TYPE == 0x00c3) {
        IERC20Minimal(token).transfer(recipient, amount);
      } else {
        // This doesn't works on Tron
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(
          ERC20_TRANSFER_SELECTOR,
          recipient,
          amount
        ));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "transfer failed");
      }
    }
  }

  function _transferCoreToken(address recipient, uint256 amount) internal {
    (bool success, ) = recipient.call{value: amount * 1e12}("");
    require(success, "Transfer failed");
  }

  /// @notice Transfer tokens to a contract using `depositWithBeneficiary`
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  /// @param contractAddr The smart contract address that will receive transferring tokens
  /// @param beneficiary The beneficiary of `depositWithBeneficiary`
  /// @param amount The value of the transfer (always in decimal 6)
  /// @param data Extra data passed to the contract
  function _transferToContract(
    uint8 tokenIndex,
    address contractAddr,
    address beneficiary,
    uint256 amount,
    uint64 data
  ) internal {
    require(Address.isContract(contractAddr), "The given recipient address is not a contract");

    amount *= _amountFactor(tokenIndex);
    if (_isCoreToken(tokenIndex)) {
      // Core tokens (e.g. ETH or BNB)
      IDepositWithBeneficiary(contractAddr).depositWithBeneficiary{value: amount}(
        address(0),
        amount,
        beneficiary,
        data
      );
    } else {
      // Stablecoins
      address token = tokenForIndex[tokenIndex];
      require(Address.isContract(token), "The given token address is not a contract");
      
      IERC20Minimal(token).approve(contractAddr, amount);
      IDepositWithBeneficiary(contractAddr).depositWithBeneficiary(
        token,
        amount,
        beneficiary,
        data
      );
    }
  }

  /// @notice Determine if token has decimal 18 and therefore need to adjust amount
  /// @param tokenIndex The index of token. See `tokenForIndex` in `MesonTokens.sol`
  function _amountFactor(uint8 tokenIndex) private pure returns (uint256) {
    if (tokenIndex <= 32) {
      return 1;
    } else if (tokenIndex == 242 && SHORT_COIN_TYPE != 0x02ca && SHORT_COIN_TYPE != 0x1771) {
      return 100;
    } else if (tokenIndex > 112 && tokenIndex <= 123) {
      return 100;
    } else if (tokenIndex > 123 && tokenIndex <= 128) {
      return 1000;
    }
    return 1e12;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

/// @title MesonTokens
/// @notice The class that stores the information of Meson's supported tokens
contract MesonTokens {
  /// @notice The whitelist of supported tokens in Meson
  /// Meson use a whitelist for supported stablecoins, which is specified on first deployment
  /// or added through `_addSupportToken` Only modify this mapping through `_addSupportToken`.
  /// key: `tokenIndex` in range of 1-255
  ///     0:       unsupported
  ///     1-32:    stablecoins with decimals 6
  ///       1, 9:    USDC, USDC.e
  ///       2, 10:   USDT, USDT.e
  ///       3:       BUSD
  ///       6:       CUSD (Viction/Tomo)
  ///       17:      PoD USDC
  ///       18:      PoD USDT
  ///       19:      PoD BUSD
  ///       32:      PoD
  ///     33-48:   stablecoins with decimals 18
  ///       33:      USDC
  ///       34:      USDT
  ///       35:      BUSD
  ///       36:      (reserved for DAI)
  ///       37:      cUSD (Celo)
  ///       39:      USDB (Blast)
  ///       40:      FDUSD
  ///       41:      BBUSD
  ///       48:      USD1
  ///     49-64:   stablecoins as core (decimals 18)
  ///       49:      USDC
  ///       52:      DAI
  ///     65-112:  3rd party tokens (decimals 18)
  ///       65:      iUSD (iZUMi Bond USD)
  ///       67:      M-BTC (Merlin BTC)
  ///       69:      MERL
  ///       71:      STONE
  ///       73:      SolvBTC.m
  ///       75:      SolvBTC
  ///       77:      SolvBTC.a
  ///       79:      uBTC
  ///       81:      xSolvBTC
  ///       83:      SolvBTC.ENA
  ///       85:      SolvBTC.JUP
  ///       87:      PUMP
  ///       89:      B2
  ///     113-123:  3rd party tokens (decimals 8)
  ///       113:     pumpBTC
  ///       114:     uniBTC
  ///       115:     cbBTC
  ///     124-128:  3rd party tokens (decimals 9)
  ///       124:     DUCK
  ///     129-190: (Unspecified)
  ///     191:     No-swap core
  ///     192-235: (Unspecified)
  ///     236-239: MATIC & MATIC equivalent
  ///       236:     PoD MATIC
  ///       238:     ERC20 MATIC
  ///       239:     MATIC as core
  ///     240-243: BTC & BTC equivalent
  ///       240:     PoD BTC
  ///       241:     ERC20 BTC (decimals 18)
  ///       242:     ERC20 BTC (decimals 8 except BNB Smart Chain & BounceBit)
  ///       243:     BTC as core
  ///     244-247: SOL & SOL equivalent
  ///       244:     PoD SOL
  ///       246:     ERC20 SOL
  ///       247:     SOL as core
  ///     248-251: BNB & BNB equivalent
  ///       248:     PoD BNB
  ///       250:     (reserved for ERC20 BNB)
  ///       251:     BNB as core
  ///     252-255: ETH & ETH equivalent
  ///       252:     PoD ETH
  ///       254:     Wrapped ETH
  ///       255:     ETH as core
  /// value: the supported token's contract address
  mapping(uint8 => address) public tokenForIndex;


  /// @notice The mapping to get `tokenIndex` from a supported token's address
  /// Only modify this mapping through `_addSupportToken`.
  /// key: the supported token's contract address
  /// value: `tokenIndex` in range of 1-255
  mapping(address => uint8) public indexOfToken;

  /// @dev This empty reserved space is put in place to allow future versions to
  /// add new variables without shifting down storage in the inheritance chain.
  /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  uint256[50] private __gap;

  function _isCoreToken(uint8 tokenIndex) internal returns (bool) {
    return (tokenIndex >= 49 && tokenIndex <= 64) || ((tokenIndex > 190) && ((tokenIndex % 4) == 3));
  }

  /// @notice Return all supported token addresses in an array ordered by `tokenIndex`
  /// This method will only return tokens with consecutive token indexes.
  function getSupportedTokens() external view returns (address[] memory tokens, uint8[] memory indexes) {
    uint8 i;
    uint8 num;
    for (i = 0; i < 255; i++) {
      if (tokenForIndex[i+1] != address(0)) {
        num++;
      }
    }
    tokens = new address[](num);
    indexes = new uint8[](num);
    uint8 j = 0;
    for (i = 0; i < 255; i++) {
      if (tokenForIndex[i+1] != address(0)) {
        tokens[j] = tokenForIndex[i+1];
        indexes[j] = i+1;
        j++;
      }
    }
  }

  function _addSupportToken(address token, uint8 index) internal {
    require(index != 0, "Cannot use 0 as token index");
    require(token != address(0), "Cannot use zero address");
    require(indexOfToken[token] == 0, "Token has been added before");
    require(tokenForIndex[index] == address(0), "Index has been used");
    if (_isCoreToken(index)) {
      require(token == address(0x1), "Core token requires adddress(0x1)");
    }
    indexOfToken[token] = index;
    tokenForIndex[index] = token;
  }

  function _removeSupportToken(uint8 index) internal {
    require(index != 0, "Cannot use 0 as token index");
    address token = tokenForIndex[index];
    require(token != address(0), "Token for the index does not exist");
    delete indexOfToken[token];
    delete tokenForIndex[index];
  }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "evmVersion": "istanbul",
  "viaIR": true,
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"premiumManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]

60806040818152346102df5781615293803803809161001e82856102e4565b83396020938491810103126102df57516001600160a01b0392838216918290036102df578251614e68808201956001600160401b03929091838811828910176102c95761042b823980600097039087f080156102bf57168451938385019063485cc95560e01b825233602487015260448601526044855260808501858110848211176102ab57808752823b1561025457507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03191683179055855194827fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8988a280511580159061024d575b610125575b865160a890816103838239f35b6060860186811085821117610239578752602786527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c85870152660819985a5b195960ca1b87870152823b156101e6575187928392905af4903d156101d5573d9081116101c15784956101b49551916101a785601f19601f84011601846102e4565b825281933d92013e610307565b5080388080808080610118565b634e487b7160e01b86526041600452602486fd5b5090506101b4929350606090610307565b865162461bcd60e51b815260048101869052602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b634e487b7160e01b89526041600452602489fd5b5087610113565b62461bcd60e51b81526084868101869052602d60a48801527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60c48801526c1bdd08184818dbdb9d1c9858dd609a1b60e488015290fd5b634e487b7160e01b88526041600452602488fd5b85513d88823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176102c957604052565b90919015610313575090565b8151156103235750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b828510610369575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935061034656fe608060405236156054577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f35b3d90fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f3fea164736f6c6343000810000a60a080604052346100315730608052614e31908161003782396080518181816108d301528181610efa01526129b10152f35b600080fdfe60806040526004361015610013575b600080fd5b60003560e01c8063051119f5146103475780631e2a60751461033e5780632335093c14610335578063264849e71461032c57806330f00f3a1461032357806335eff30f1461031a5780633659cfe61461031157806337b90a4f14610308578063485cc955146102ff5780634f1ef286146102f6578063515147ab146102ed57806352d1902d146102e457806354d6a2b7146102db57806358d9b4e1146102d257806360a2da98146102c957806360b068be146102c05780637234cd95146102b7578063741c8e2d146102ae5780637fe0282b146102a5578063827c87cc1461029c57806389a734c0146102935780638b0a77651461028a5780638f487dc9146102815780639fa1027914610278578063a5c9c66c1461026f578063ab115fd814610266578063b805f3211461025d578063c11d9ecb14610254578063c5d7ca001461024b578063c8173c4414610242578063cb4f999b14610239578063ce7f79b914610230578063d3c7c2c714610227578063d3e95ea41461021e578063d4f8232214610215578063decf2a481461020c578063eba7fb7714610203578063f1d2ec1d146101fa578063f2fde38b146101f1578063ff22f272146101e85763ff378719146101e057600080fd5b61000e6125b1565b5061000e6124af565b5061000e612477565b5061000e61234c565b5061000e61232b565b5061000e61228f565b5061000e612249565b5061000e612214565b5061000e6120f8565b5061000e611fcd565b5061000e611eda565b5061000e611e49565b5061000e611da0565b5061000e611cf6565b5061000e611c2e565b5061000e6119fd565b5061000e61182f565b5061000e611737565b5061000e6115f6565b5061000e6115bb565b5061000e611577565b5061000e6113ed565b5061000e6113a1565b5061000e61130b565b5061000e611204565b5061000e611150565b5061000e611086565b5061000e611061565b5061000e610fab565b5061000e610ee6565b5061000e610d2c565b5061000e610cb4565b5061000e610b1d565b5061000e610a26565b5061000e6108af565b5061000e610798565b5061000e61067a565b5061000e610595565b5061000e610557565b5061000e6104b7565b5061000e6103bc565b600435906001600160a01b038216820361000e57565b602435906001600160a01b038216820361000e57565b606435906001600160a01b038216820361000e57565b604435906001600160a01b038216820361000e57565b35906001600160a01b038216820361000e57565b503461000e57602036600319011261000e576103d6610350565b3360005260996020527f475b83c893df40ee19fd0783cf26478cdb58478dff65bb62560e1e7c36e0f22f6104b264ffffffffff604060002054169261041c8415156133c8565b6000848152609a602052604090205461045090610449906001600160a01b03165b6001600160a01b031690565b3314613372565b61047e8461047861046e6104638561053d565b5464ffffffffff1690565b64ffffffffff1690565b14613420565b61049861048a8261053d565b805464ffffffffff19169055565b6040516001600160a01b0390911681529081906020820190565b0390a2005b503461000e57602036600319011261000e57606060406000600435815260ce602052205460018060a01b0390818160281c169182156000146105135760005b60405193845216602083015260018060c81b031615156040820152f35b8061053664ffffffffff841664ffffffffff16600052609a602052604060002090565b54166104f6565b6001600160a01b0316600090815260996020526040902090565b503461000e57602036600319011261000e576001600160a01b03610579610350565b166000526066602052602060ff60406000205416604051908152f35b50602036600319011261000e576106786004356105b760018260f81c14612ebd565b6105cb61110061ffff8360081c1614612f09565b6105fb6105da60ff83166141be565b60ff6105f36105ed828660181c166141be565b60ff1690565b911614612f4f565b600081815260ce6020526040902061062f906001600160c81b0390610628905b546001600160c81b031690565b1615612fa5565b610673611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b42908560301c16612d38565b61066d610e108211613053565b10613095565b613d69565b005b503461000e57602036600319011261000e57610694610350565b3360005260996020527fc94089e0c0b1b79fdecc6e64fb759cdd390590a15c7e50d281e681ea8273261c6104b264ffffffffff60406000205416926106da8415156133c8565b6000848152609a60205260409020546106ff90610449906001600160a01b031661043d565b6107128461047861046e6104638561053d565b610750816107318664ffffffffff16600052609a602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b604080513381526001600160a01b03909216602083015290918291820190565b6024359064ffffffffff8216820361000e57565b6044359064ffffffffff8216820361000e57565b503461000e57604036600319011261000e576004356107b5610770565b600082815260ce60205260409020546001600160c81b0381169291906107dd6001851161353f565b64ffffffffff80911661086a5760009361080c61084093836108016104633361053d565b91169316831461386b565b176108218360005260ce602052604060002090565b80546001600160c81b0319166001600160c81b03909216919091179055565b604051907f60a99b51ae498c44acbbe11031aed2a06a32be66d2122e6e2a7a16c087865cc98383a2f35b60405162461bcd60e51b815260206004820152601b60248201527f5377617020626f6e64656420746f20616e6f7468657220706f6f6c00000000006044820152606490fd5b503461000e57602036600319011261000e576108c9610350565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169190610902308414156125ee565b61091f600080516020614e0583398151915293828554161461264f565b61092f8161013454163314612b37565b6040519061093c82610c26565b600082527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109765750506106789150612779565b6020600491604094939451928380926352d1902d60e01b825286165afa600091816109d1575b506109be5760405162461bcd60e51b8152806109ba6004820161272a565b0390fd5b610678936109cc91146126cc565b612809565b6109f391925060203d81116109fa575b6109eb8183610c69565b8101906126b0565b903861099c565b503d6109e1565b604090600319011261000e576004359060243565ffffffffffff8116810361000e5790565b50610a3036610a01565b610a3b82151561323e565b64ffffffffff80821690610a50821515613284565b3360005260996020526040600020541603610ac75765ffffffffffff81610a977f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7693612d08565b610aa2858254612d71565b9055610ab5843360ff8460281c166147c2565b604051938452169180602081016104b2565b60405162461bcd60e51b815260206004820152602860248201527f4e65656420616e20617574686f72697a65642061646472657373206173207468604482015267329039b4b3b732b960c11b6064820152608490fd5b503461000e57604036600319011261000e57610b37610350565b610b83610b42610366565b60005492610b6760ff8560081c161580958196610c01575b8115610be1575b50613db7565b83610b7a600160ff196000541617600055565b610bc857613e1a565b610b8957005b610b9961ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a1005b610bdc61010061ff00196000541617600055565b613e1a565b303b15915081610bf3575b5038610b61565b6001915060ff161438610bec565b600160ff8216109150610b5a565b50634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b03821117610c4157604052565b610c49610c0f565b604052565b606081019081106001600160401b03821117610c4157604052565b90601f801991011681019081106001600160401b03821117610c4157604052565b6020906001600160401b038111610ca7575b601f01601f19160190565b610caf610c0f565b610c9c565b50604036600319011261000e57610cc9610350565b602435906001600160401b03821161000e573660238301121561000e57816004013590610cf582610c8a565b91610d036040519384610c69565b808352366024828601011161000e576020816000926024610678970183870137840101526129a7565b503461000e57608036600319011261000e576000600435610e68610d7a610d5161037c565b610d6060018560f81c14612ebd565b610d7461110061ffff8660201c1614612f09565b83613e27565b610daa6001600160501b03610628610d9d84600052610101602052604060002090565b546001600160501b031690565b610e4d610db96104633361053d565b69ffffffffff000000000064ffffffffff80831692610dd9841515613481565b610dfa610df3610de842612d45565b938a60301c16612d20565b83106134e5565b610e0388613e46565b610e22610e1a8660ff60281b8c60101b1617612d08565b918254612d38565b9055610e2d88614039565b9081610e92575b505060281b161791600052610101602052604060002090565b906001600160501b03166001600160501b0319825416179055565b604051907fbfb879c34323c5601fafe832c3a8a1e31e12c288695838726ddeada86034edb48383a2f35b60016000526066602052610edd90610e1a90610ed890610ec2600080516020614de58339815191525b5460ff1690565b60281b60ff60281b1664ffffffffff9091161790565b612d08565b90553880610e34565b503461000e57600036600319011261000e577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610f4557604051600080516020614e058339815191528152602090f35b0390f35b60405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c6044820152771b1959081d1a1c9bdd59da0819195b1959d85d1958d85b1b60421b6064820152608490fd5b503461000e57602036600319011261000e57600435600081815260ce602052604081205490919061103790610feb60016001600160c81b0383161161353f565b64ffffffffff61100142828660301c1610613c81565b83855260ce6020526040852080546001600160c81b031916905560d084901c169060281c6001600160a01b031660ff8416614907565b604051907ff6b6b4f7a13f02512c1b3aa8dcc4a07d7775a6a4becbd439efcbd37c5408e67f8383a2f35b503461000e57604036600319011261000e576000600435610e68610d7a610d51610366565b503461000e57604036600319011261000e576110a0610366565b6110ae600091600435613e27565b81526101016020526040812054906001600160501b0382166001036110f857505060016000905b604080516001600160a01b0392909216825264ffffffffff929092166020820152f35b64ffffffffff8281168252609a60205260409091205460289290921c16906001600160a01b03166110d5565b602435906001600160c81b038216820361000e57565b606435906001600160c81b038216820361000e57565b50606036600319011261000e5761067860043561116b611124565b611173610392565b9161118360018260f81c14612ebd565b61119761110061ffff8360081c1614612f09565b6111a66105da60ff83166141be565b600081815260ce602052604090206111ca906001600160c81b03906106289061061b565b6111ef611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613be2565b6004359060ff8216820361000e57565b503461000e57606036600319011261000e5761121e6111f4565b6024359061122a610784565b610134546001600160a01b03929164ffffffffff9161124c9085163314612b37565b169182600052609a602052604060002054161561129c576112989160ff60281b6112909260281b1661127d81612d08565b611288868254612d38565b905517612d08565b918254612d71565b9055005b60405162461bcd60e51b8152602060048201526019602482015278141bdbdb081a5b99195e081b9bdd081c9959da5cdd195c9959603a1b6044820152606490fd5b608090600319011261000e57600435906024356001600160a01b038116810361000e57906044359060643590565b503461000e5761067861131d366112dd565b9261133060018260f89594951c14612ebd565b61134461110061ffff8360081c1614612f09565b6113536105da60ff83166141be565b600081815260ce60205260409020611377906001600160c81b03906106289061061b565b61139c611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b6130d6565b503461000e57602036600319011261000e576001600160a01b036113c3610350565b166000526099602052602064ffffffffff60406000205416604051908152f35b8015150361000e57565b503461000e5760a036600319011261000e57600060043561140c61037c565b608435611418816113e3565b61142f61061b8460005260ce602052604060002090565b61144460016001600160c81b0383161161353f565b61144d42612d54565b906114ab64ffffffffff948593848860301c161088146115485761148e61147e8860005260ce602052604060002090565b80546001600160c81b0319169055565b602883901c6001600160a01b0316906044359060243590896142f7565b16908414611504576114ca6114d79160ff60281b8560281b1617612d08565b918360d01c168254612d71565b90555b604051907f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c98383a2f35b906115336115266115439364ffffffffff16600052609a602052604060002090565b546001600160a01b031690565b908360d01c169060ff8416614907565b6114da565b61157261155f8860005260ce602052604060002090565b80546001600160c81b0319166001179055565b61148e565b503461000e57602036600319011261000e5760043564ffffffffff811680910361000e57600052609a602052602060018060a01b0360406000205416604051908152f35b503461000e57602036600319011261000e5760ff60281b6115da6111f4565b60281b16600052609b6020526020604060002054604051908152f35b5065ffffffffffff7f7d7d1df74ef3a6434d8d63dc0a25d13d5fa94dbe738c38a3cce26e6f892e2a7661162836610a01565b611635829492151561323e565b64ffffffffff8116611648811515613284565b61167760018060a01b036116706115268464ffffffffff16600052609a602052604060002090565b16156132d0565b61168f61168961046e6104633361053d565b1561331c565b6116ae336107318364ffffffffff16600052609a602052604060002090565b6116d2816116bb3361053d565b9064ffffffffff1664ffffffffff19825416179055565b6116db82612d08565b6116e6868254612d71565b90556116f9853360ff8560281c166147c2565b6040513381527fb8d9c35a714d4e29eaf036b9bf8183a093c5573ac809453b4e8434e25c9126d290602090a2604051938452169180602081016104b2565b503461000e5760006117cc61103761174e366112dd565b83875260ce6020526040872054939592939192919061177860016001600160c81b0384161161353f565b64ffffffffff9361178f42868a60301c1610613c81565b60405160208101906117b4816117a68a8d86613220565b03601f198101835282610c69565b51902060289390931c6001600160a01b031692614509565b6117e361147e8560005260ce602052604060002090565b8360d01c169060ff8416614907565b60a090600319011261000e576004359060243590604435906001600160a01b0390606435828116810361000e5791608435908116810361000e5790565b503461000e5760006118fc6119386118e6611849366117f2565b93969194909261185a3233146135c2565b61186f4264ffffffffff8a60301c1611613619565b6118836001600160a01b03861615156131d5565b6118d584600160ce1b8a16159788156119e0575b6118a1828c613e27565b936118ce60016001600160501b036118c7610d9d89600052610101602052604060002090565b161161353f565b888c6142f7565b600052610101602052604060002090565b805469ffffffffffffffffffff19166001179055565b61190585613e46565b926119b0575b611914856140a4565b80611972575b5061192485614039565b80611962575b5060ff8560181c1685613665565b604051907ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad28383a2f35b61196c90836149e1565b3861192a565b928361197d91612d38565b926119a8611290610ed861199089614158565b899064ffffffffff60ff60281b91169160101b161790565b90553861191a565b6119c36119bc86613ef4565b8094612d38565b926119d961129060ff60281b8860101b16612d08565b905561190b565b610135546119f8906001600160a01b03163314612cb2565b611897565b503461000e576000611938611a11366117f2565b91611a2460018660f89897981c14612ebd565b611a3861110061ffff8860201c1614612f09565b611a433233146135c2565b611a576001600160a01b03841615156131d5565b85611ae26118e6600160ce1b831615968715611c11575b611a788685613e27565b90611a9c6001600160501b03610628610d9d85600052610101602052604060002090565b86611aa96104633361053d565b9664ffffffffff928a848a1698611ac18a1515613481565b8d8315611be85750611add6118d59642908360301c1611613619565b6142f7565b611aeb87613e46565b94611b0160ff60281b8960101b16928317612d08565b611b0c878254612d38565b9055611bc7575b50611b1d866140a4565b80611b89575b50611b2d86614039565b80611b42575b505060ff8560181c1685613665565b60016000526066602052611b8291611b6f90610ed890610ec2600080516020614de5833981519152610ebb565b611b7a828254612d38565b9055836149e1565b3880611b33565b9384611b9491612d38565b93611bbf611290610ed8611ba78a614158565b8a9064ffffffffff60ff60281b91169160101b161790565b905538611b23565b93611be0611290611bda6119bc8a613ef4565b96612d08565b905538611b13565b95505050505050156118d55761013554611c0c906001600160a01b03163314612cb2565b6118d5565b61013554611c29906001600160a01b03163314612cb2565b611a6e565b503461000e57602036600319011261000e57610678611c4b610350565b61013554611c63906001600160a01b03163314612cb2565b612e17565b6020906001600160401b038111611c81575b60051b0190565b611c89610c0f565b611c7a565b81601f8201121561000e57803591611ca583611c68565b92611cb36040519485610c69565b808452602092838086019260051b82010192831161000e578301905b828210611cdd575050505090565b813560ff8116810361000e578152908301908301611ccf565b503461000e57604036600319011261000e576001600160401b0360043581811161000e573660238201121561000e578060040135611d3381611c68565b91611d416040519384610c69565b81835260209160248385019160051b8301019136831161000e57602401905b828210611d89576024358587821161000e57611d83610678923690600401611c8e565b90612b7d565b838091611d95846103a8565b815201910190611d60565b503461000e57608036600319011261000e57610678600435611dc061113a565b90611dd060018260f81c14612ebd565b611de461110061ffff8360081c1614612f09565b611df36105da60ff83166141be565b600081815260ce60205260409020611e17906001600160c81b03906106289061061b565b611e3c611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b60443590602435906138d8565b50610678611e56366117f2565b93611e6960018260f89694961c14612ebd565b611e7d61110061ffff8360081c1614612f09565b611e8c6105da60ff83166141be565b600081815260ce60205260409020611eb0906001600160c81b03906106289061061b565b611ed5611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613cc4565b503461000e57602036600319011261000e57611ef46111f4565b610134546001600160a01b0390611f0e9082163314612b37565b60ff8216611f1d811515614bb3565b6000526065602052604060002054168015611f7d576001600160a01b03166000908152606660205260409020805460ff1916905561067890611f6d905b60ff166000526065602052604060002090565b80546001600160a01b0319169055565b60405162461bcd60e51b815260206004820152602260248201527f546f6b656e20666f722074686520696e64657820646f6573206e6f74206578696044820152611cdd60f21b6064820152608490fd5b503461000e5765ffffffffffff7f34c3d1c46f89307d63d8818fcc5c2a9c07a5f7a01ea4319bfba1899f40c6f40061200436610a01565b612011829492151561323e565b64ffffffffff8116612024811515613284565b600052609a60205261204460018060a01b03604060002054163314613372565b61204d81612d08565b80549085820391821161206d575b55610ab5843360ff8460281c16614907565b612075612c53565b61205b565b6040810190604081528251809252606081019160208094019060005b8181106120db575050508281830391015281808451928381520193019160005b8281106120c4575050505090565b835160ff16855293810193928101926001016120b6565b82516001600160a01b031685529385019391850191600101612096565b503461000e576000806003193601126122115780805b60ff80821610156121535761212b61043d611526611f5a846141ac565b61213e575b61213990612c6a565b61210e565b9161214b61213991612c6a565b929050612130565b5060ff8092169061216c61216683614b81565b92614b81565b92815b818082161061218a57505050610f416040519283928361207a565b61219c61043d611526611f5a846141ac565b6121af575b6121aa90612c6a565b61216f565b916122096121aa916122046121c9611526611f5a886141ac565b6121e9868416916121da838b612c88565b6001600160a01b039091169052565b6121fc6121f5886141ac565b918a612c88565b9060ff169052565b612c6a565b9290506121a1565b80fd5b503461000e57604036600319011261000e576020612241612233610350565b61223b610366565b906145c3565b604051908152f35b503461000e57604036600319011261000e57612263610350565b60243560ff8116810361000e576106789161228a60018060a01b0361013454163314612b37565b614ce3565b50604036600319011261000e576106786004356122aa611124565b906122ba60018260f81c14612ebd565b6122ce61110061ffff8360081c1614612f09565b6122dd6105da60ff83166141be565b600081815260ce60205260409020612301906001600160c81b03906106289061061b565b612326611c2061066064ffffffffff61065464174876e800828760d01c161115612fe7565b613b44565b503461000e57600036600319011261000e57604051601160f81b8152602090f35b503461000e57604036600319011261000e57600060043561241761240461237a612374610366565b84613e27565b612392610d9d82600052610101602052604060002090565b6123a760016001600160501b0383161161353f565b64ffffffffff906123be42838360281c1610613581565b166123c885613e46565b6123df6112908360ff60281b8960101b1617612d08565b90556123ea85614039565b9081612441575b5050600052610101602052604060002090565b805469ffffffffffffffffffff19169055565b604051907fac7d23c4f0137a4cc35b0e4b4bc8061ea6cb65805e87ceb0a77ca0c85814858c8383a2f35b6001600052606660205261246e9061129090610ed890610ec2600080516020614de5833981519152610ebb565b905538806123f1565b503461000e57602036600319011261000e57610678612494610350565b6124aa60018060a01b0361013454163314612b37565b612d7e565b503461000e57602036600319011261000e576124c9610350565b6001600160a01b03811660009081526099602052604090205464ffffffffff91908216612560576104b27fd49cde4f679ccef3d23ff07aae4f6845e1c661e23e9fe6a54da26f0723fb695f916104986125246104633361053d565b948516946125338615156133c8565b61255761044961043d6115268464ffffffffff16600052609a602052604060002090565b6116bb8361053d565b60405162461bcd60e51b815260206004820152602360248201527f4164647220697320617574686f72697a656420666f7220616e6f7468657220706044820152621bdbdb60ea1b6064820152608490fd5b503461000e57602036600319011261000e5760ff6125cd6111f4565b166000526065602052602060018060a01b0360406000205416604051908152f35b156125f557565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561265657565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b9081602091031261000e575190565b506040513d6000823e3d90fd5b156126d357565b60405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b60809060208152602e60208201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960408201526d6f6e206973206e6f74205555505360901b60608201520190565b803b156127ae57600080516020614e0583398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b61281281612779565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600083a2825115801590612919575b61285857505050565b813b156128c85750600082819260206128c595519201905af4612879612977565b6040519161288683610c4e565b602783527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020840152660819985a5b195960ca1b6040840152612abc565b50565b62461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608490fd5b50600061284f565b61292a81612779565b6040516001600160a01b0382167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600083a282511580159061296f5761285857505050565b50600161284f565b3d156129a2573d9061298882610c8a565b916129966040519384610c69565b82523d6000602084013e565b606090565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692906129e0308514156125ee565b6129fd600080516020614e0583398151915294828654161461264f565b612a0d8161013454163314612b37565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612a45575050612a439150612779565b565b6020600491604094939451928380926352d1902d60e01b825286165afa60009181612a9c575b50612a895760405162461bcd60e51b8152806109ba6004820161272a565b612a4393612a9791146126cc565b612921565b612ab591925060203d81116109fa576109eb8183610c69565b9038612a6b565b90919015612ac8575090565b815115612ad85750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b828510612b1e575050604492506000838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350612afb565b15612b3e57565b60405162461bcd60e51b815260206004820152601760248201527621b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606490fd5b9091612b9560018060a01b0361013454163314612b37565b8151835103612bf75760005b825160ff821690811015612bf0579061220482612be5612bde612bd7612bca612beb978a612c88565b516001600160a01b031690565b9289612c88565b5160ff1690565b90614ce3565b612ba1565b5050915050565b60405162461bcd60e51b815260206004820152602e60248201527f546f6b656e7320616e6420696e64657865732073686f756c642068617665207460448201526d0d0ca40e6c2daca40d8cadccee8d60931b6064820152608490fd5b50634e487b7160e01b600052601160045260246000fd5b60ff6001911660ff8114612c7c570190565b612c84612c53565b0190565b8051821015612c9c5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b15612cb957565b60405162461bcd60e51b815260206004820152602160248201527f43616c6c6572206973206e6f7420746865207072656d69756d206d616e6167656044820152603960f91b6064820152608490fd5b65ffffffffffff16600052609b602052604060002090565b61012b19810191908211612d3057565b612a43612c53565b91908203918211612d3057565b906104b08201809211612d3057565b90610e108201809211612d3057565b90601b8201809211612d3057565b91908201809211612d3057565b6001600160a01b03908116908115612dd35761013480546001600160a01b0319811684179091556040519116907f8934ce4adea8d9ce0d714d2c22b86790e41b7731c84b926fbbdc1d40ff6533c990600090a3565b606460405162461bcd60e51b815260206004820152602060248201527f4e6577206f776e65722063616e6e6f74206265207a65726f20616464726573736044820152fd5b6001600160a01b03908116908115612e6c5761013580546001600160a01b0319811684179091556040519116907f4798f31ad3d0ccde6359edf35fc39b882e4e1cff2968ca749b72074d373db27a90600090a3565b60405162461bcd60e51b815260206004820152602360248201527f4e6577207072656d69756d206d616e61676572206265207a65726f206164647260448201526265737360e81b6064820152608490fd5b15612ec457565b60405162461bcd60e51b815260206004820152601a60248201527f496e636f727265637420656e636f64696e672076657273696f6e0000000000006044820152606490fd5b15612f1057565b60405162461bcd60e51b815260206004820152601760248201527629bbb0b8103737ba103337b9103a3434b99031b430b4b760491b6044820152606490fd5b15612f5657565b60405162461bcd60e51b815260206004820152602160248201527f496e2026206f757420746f6b656e20747970657320646f206e6f74206d6174636044820152600d60fb1b6064820152608490fd5b15612fac57565b60405162461bcd60e51b81526020600482015260136024820152725377617020616c72656164792065786973747360681b6044820152606490fd5b15612fee57565b60405162461bcd60e51b815260206004820152603760248201527f466f7220736563757269747920726561736f6e2c20616d6f756e742063616e6e6044820152766f742062652067726561746572207468616e203130306b60481b6064820152608490fd5b1561305a57565b60405162461bcd60e51b815260206004820152601360248201527245787069726520747320746f6f206561726c7960681b6044820152606490fd5b1561309c57565b60405162461bcd60e51b815260206004820152601260248201527145787069726520747320746f6f206c61746560701b6044820152606490fd5b926131ac92613135916130f361110061ffff8860201c1614612f09565b6131076001600160a01b03851615156131d5565b604051602081019061311e816117a6888b86613220565b519020610135546001600160a01b03169290614509565b64ffffffffff9061319e613154838660d01c16938660581c1684612d38565b92613187600160ff60281b61316f82828b60281b1617612d08565b61317a858254612d71565b90558860101b1617612d08565b613192858254612d38565b90553360ff87166147c2565b3360ff8560181c1685613665565b7ffa628b578e095243f0544bfad9255f49d79d03a5bbf6c85875d05a215e247ad26000604051a2565b156131dc57565b606460405162461bcd60e51b815260206004820152602060248201527f526563697069656e742063616e6e6f74206265207a65726f20616464726573736044820152fd5b90815260609190911b6001600160601b031916602082015260340190565b1561324557565b60405162461bcd60e51b8152602060048201526017602482015276416d6f756e74206d75737420626520706f73697469766560481b6044820152606490fd5b1561328b57565b60405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f7420757365203020617320706f6f6c20696e6465780000000000006044820152606490fd5b156132d757565b60405162461bcd60e51b815260206004820152601d60248201527f506f6f6c20696e64657820616c726561647920726567697374657265640000006044820152606490fd5b1561332357565b60405162461bcd60e51b815260206004820152602160248201527f5369676e6572206164647265737320616c7265616479207265676973746572656044820152601960fa1b6064820152608490fd5b1561337957565b60405162461bcd60e51b815260206004820152602160248201527f4e6565642074686520706f6f6c206f776e657220617320746865207369676e656044820152603960f91b6064820152608490fd5b156133cf57565b60405162461bcd60e51b815260206004820152602360248201527f546865207369676e657220646f6573206e6f74207265676973746572206120706044820152621bdbdb60ea1b6064820152608490fd5b1561342757565b60405162461bcd60e51b815260206004820152602c60248201527f41646472206973206e6f7420617574686f72697a656420666f7220746865207360448201526b1a59db995c89dcc81c1bdbdb60a21b6064820152608490fd5b1561348857565b60405162461bcd60e51b815260206004820152602f60248201527f43616c6c6572206e6f7420726567697374657265642e2043616c6c206465706f60448201526e39b4ba20b7322932b3b4b9ba32b91760891b6064820152608490fd5b156134ec57565b60405162461bcd60e51b815260206004820152602560248201527f43616e6e6f74206c6f636b20626563617573652065787069726554732069732060448201526439b7b7b71760d91b6064820152608490fd5b1561354657565b60405162461bcd60e51b815260206004820152601360248201527214ddd85c08191bd95cc81b9bdd08195e1a5cdd606a1b6044820152606490fd5b1561358857565b60405162461bcd60e51b815260206004820152601260248201527153776170207374696c6c20696e206c6f636b60701b6044820152606490fd5b156135c957565b60405162461bcd60e51b815260206004820152602260248201527f43616e6e6f742062652063616c6c6564207468726f75676820636f6e74726163604482015261747360f01b6064820152608490fd5b1561362057565b60405162461bcd60e51b815260206004820152601e60248201527f43616e6e6f742072656c656173652062656361757365206578706972656400006044820152606490fd5b9093929190600160cf1b8116613856576001600160401b036136a19160801c1693613692843b1515614a58565b61369b86614aba565b90613ee1565b936136ab81614b41565b15613740575060405163bff4163f60e01b815260006004820152602481018590526001600160a01b0391821660448201526001600160401b039390931660648401529192602092849260849284929091165af18015613733575b61370c5750565b6128c59060203d811161372c575b6137248183610c69565b810190614713565b503d61371a565b61373b6126bf565b613705565b61152661375a9160ff166000526065602052604060002090565b91613767833b15156146b5565b60405163095ea7b360e01b81526001600160a01b038281166004830152602482018790526020968795909260009291908781604481878688165af18015613849575b61382c575b5060405163bff4163f60e01b81526001600160a01b03918216600482015260248101949094529490941660448301526001600160401b03959095166064820152938492608492849291165af1801561381f575b613809575050565b816128c592903d1061372c576137248183610c69565b6138276126bf565b613801565b61384290883d8a1161372c576137248183610c69565b50386137ae565b6138516126bf565b6137a9565b50508161386257505050565b612a4392614907565b1561387257565b60405162461bcd60e51b815260206004820152603860248201527f5369676e65722073686f756c6420626520616e20617574686f72697a6564206160448201527719191c995cdcc81bd9881d1a194819da5d995b881c1bdbdb60421b6064820152608490fd5b9290613a2b613a3a93926020600060018060a01b038360281c169564ffffffffff9586851680151580613b3a575b613b1e575b5061391788151561426b565b6001600160ff1b038216916139f190613936906105ed9060ff1c612d63565b926139596fa2a8918ca85bafe22016d0b997e4df60600160ff1b038211156142b7565b600160cb1b8c1615158560088e901c61ffff1660c3148114613a9957508514613a7057780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519998560391b6117a66139c68e5b6040519283918b83019586909160399266ffffffffffffff1916825260198201520190565b519020925b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15613a63575b600051613a17906001600160a01b031685146142b7565b6108218660005260ce602052604060002090565b8360d01c169060ff84166147c2565b7f5ce4019f772fda6cb703b26bce3ec3006eb36b73f1d3a0eb441213317d9f5e9d6000604051a2565b613a6b6126bf565b613a00565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b6117a66139c68e6139a1565b908614613ae957508b604051613ae0816117a68a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b519020926139cb565b808d6040925287812088527f9862d877599564bcd97c37305a7b0fdbe621d9c2a125026f2ad601f754a75abc815220926139cb565b613b349088613b2c3361053d565b54161461386b565b3861390b565b5088331415613906565b90602881901c6001600160a01b031633819003613b8b57613b76613a3a926108218560005260ce602052604060002090565b64ffffffffff8360d01c169060ff84166147c2565b60405162461bcd60e51b815260206004820152602960248201527f5472616e73616374696f6e2073686f756c642062652073656e742066726f6d2060448201526834b734ba34b0ba37b960b91b6064820152608490fd5b916001600160a01b0381163303613c2457613b76613a3a928460005260ce60205260406000209060018060c81b031666ffffffffffffff60c81b825416179055565b60405162461bcd60e51b815260206004820152602f60248201527f5472616e73616374696f6e2073686f756c642062652073656e742066726f6d2060448201526e636f6e74726163744164647265737360881b6064820152608490fd5b15613c8857565b60405162461bcd60e51b815260206004820152601460248201527314ddd85c081a5cc81cdd1a5b1b081b1bd8dad95960621b6044820152606490fd5b93928092613cd692613d3395876142f7565b600083815260ce6020526040902080546001600160c81b031916600117905564ffffffffff8360d01c1690600160ff60281b8560281b1617600052609b6020526040600020805490838201809211613d5c575b5560ff84166147c2565b7f8d92c805c252261fcfff21ee60740eb8a38922469a7e6ee396976d57c22fc1c96000604051a2565b613d64612c53565b613d29565b613d3364ffffffffff8260d01c16600160ff60281b8460281b1617600052609b6020526040600020805490828201809211613daa575b553360ff84166147c2565b613db2612c53565b613d9f565b15613dbe57565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b90611c63612a4392612d7e565b90613e406117a691604051928391602083019586613220565b51902090565b613e6a64ffffffffff91828160d01c16928160581c168303928311613e8157613fa2565b8103908111613e765790565b613e7e612c53565b90565b613e89612c53565b613fa2565b6005908060001904821181151516613ea4570290565b613eac612c53565b0290565b6103e8908060001904821181151516613ea4570290565b64e8d4a51000908060001904821181151516613ea4570290565b8060001904821181151516613ea4570290565b60ff811660fc8110613f355750613f23613f1b64ffffffffff6101f4935b60d01c16613e8e565b612710900490565b9080821115613f30575090565b905090565b60f88110613f535750613f23613f1b64ffffffffff61138893613f12565b60f48110613f715750613f23613f1b64ffffffffff6101f493613f12565b60f011613f8c57613f23613f1b64ffffffffff600a93613f12565b613f23613f1b64ffffffffff6207a12093613f12565b60bf60ff8260181c161080614029575b613fbc5750600090565b61ffff90818160a01c16918214613fdf5750613fda613e7e916140eb565b613eb0565b905064ffffffffff90818160d01c16918160581c16820391821161401c575b600160ce1b81161561400e575090565b61401790613ef4565b613e6a565b614024612c53565b613ffe565b5061084160c41b81811614613fb2565b61404281613fa2565b90811515908161405457505050600090565b61ffff61407591612710938560001904851116614097575b60b01c166140eb565b91821561408157020490565b634e487b7160e01b600052601260045260246000fd5b61409f612c53565b61406c565b6140ad816140c7565b6140b75750600090565b61ffff613e7e9160a01c166140eb565b600160cf1b8116151590816140da575090565b600360c91b16600160c91b14919050565b6103e88082111561415457613e7e916103e7198101908111614147575b6123289081810692830180931161413a575b04604d811161412d575b600a0a90613ee1565b614135612c53565b614124565b614142612c53565b61411a565b61414f612c53565b614108565b5090565b614161816140c7565b61416b5750600090565b60b01c61ffff16620100000164ffffffffff8111613e765790565b60ff604f199116019060ff8211612d3057565b60ff601f199116019060ff8211612d3057565b60ff60019116019060ff8211612d3057565b60ff811660c081106141d4575060021c603f1690565b604081116141e3575050600090565b6070811161420957506142046141fb613e7e926141ac565b60011c607f1690565b614199565b608010156142625760405162461bcd60e51b8152602060048201526024808201527f546f6b656e20696e646578206e6f7420616c6c6f77656420666f72207377617060448201526370696e6760e01b6064820152608490fd5b613e7e90614186565b1561427257565b60405162461bcd60e51b815260206004820152601e60248201527f5369676e65722063616e6e6f7420626520656d707479206164647265737300006044820152606490fd5b156142be57565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b612a43946001600160a01b0316936020936000939290916143e39161431d88151561426b565b6001600160ff1b03821691614338906105ed9060ff1c612d63565b9461435b6fa2a8918ca85bafe22016d0b997e4df60600160ff1b038411156142b7565b600160cb1b8216151561ffff88600885901c821660c3148114614438575050871461441157780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d051a998560391b916139c6905b6117a66040519384928c8401968791604d939166ffffffffffffff1916835260198301526bffffffffffffffffffffffff199060601b1660398201520190565b838052039060015afa15614404575b6000516001600160a01b0316146142b7565b61440c6126bf565b6143f2565b780caa2927a71029b4b3b732b21026b2b9b9b0b3b29d0519990560391b916139c6906143a3565b90939291891461449a57506040517f19457468657265756d205369676e6564204d6573736167653a0a3532000000008a8201908152601c81019390935260609190911b6001600160601b031916603c830152909150613ae081605084016117a6565b9160c3604094828c1c161489146144e2577f28cf5b919ed55db2b14d9e8b261a523eafb98bab117d3a8a56e559791415d17c915b6014528252603482208952815220926139cb565b7f743e50106a7f059b52151dd4ba27a5f6c87b925ddfbdcf1c332e800da4b3df92916144ce565b600060ff602092614590612a4397959660018060a01b038097169761452f89151561426b565b600180861b03821691851c93601b85018095116145b6575b6145686fa2a8918ca85bafe22016d0b997e4df606001881b038411156142b7565b6040519586951690859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156145a9575b60005116146142b7565b6145b16126bf565b61459f565b6145be612c53565b614547565b60018060a01b0380911660005260666020526040600020549116600052609960205264ffffffffff604060002054168015801561461d575b6146165760ff60281b6146129260281b1617612d08565b5490565b5050600090565b5060ff8216156145fb565b1561462f57565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b1561467a57565b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606490fd5b156146bc57565b60405162461bcd60e51b815260206004820152602960248201527f54686520676976656e20746f6b656e2061646472657373206973206e6f7420616044820152680818dbdb9d1c9858dd60ba1b6064820152608490fd5b9081602091031261000e5751613e7e816113e3565b1561472f57565b60405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b6044820152606490fd5b1561477157565b60405162461bcd60e51b815260206004820152602360248201527f6d73672e76616c756520646f6573206e6f74206d617463682074686520616d6f6044820152621d5b9d60ea1b6064820152608490fd5b906147ce831515614628565b6147d782614b41565b156147f15750506147ea612a4391613ec7565b341461476a565b8160009291836117a6614882614848612a439861369b614822611526879a60ff166000526065602052604060002090565b976148376001600160a01b038a161515614673565b614843893b15156146b5565b614aba565b6040516323b872dd60e01b602082019081526001600160a01b03909616602482015230604482015260648101919091529182906084820190565b51925af161488e612977565b8161489a575b50614728565b80518015925082156148af575b505038614894565b6148c29250602080918301019101614713565b38806148a7565b156148d057565b60405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b91909161491381614b41565b156149225750612a43916149e1565b60009190612a4393836117a661499a614966839661369b60018060a01b036149578960ff166000526065602052604060002090565b541697614843893b15156146b5565b60405163a9059cbb60e01b602082019081526001600160a01b03909616602482015260448101919091529182906064820190565b51925af16149a6612977565b816149b2575b506148c9565b80518015925082156149c7575b5050386149ac565b6149da9250602080918301019101614713565b38806149bf565b60008092819264e8d4a5100082841904811183151516614a4b575b6040519202905af1614a0c612977565b5015614a1457565b60405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606490fd5b614a53612c53565b6149fc565b15614a5f57565b60405162461bcd60e51b815260206004820152602d60248201527f54686520676976656e20726563697069656e742061646472657373206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b60ff1660208111614acb5750600190565b60f2811480614b39575b80614b31575b15614ae65750606490565b6070811180614b26575b15614afb5750606490565b607b81119081614b1a575b50614b145764e8d4a5100090565b6103e890565b60809150111538614b06565b50607b811115614af0565b506001614adb565b506001614ad5565b60ff81169060318210159182614b75575b8215614b5d57505090565b60be10915081614b6b575090565b6003915081161490565b60408111159250614b52565b90614b8b82611c68565b614b986040519182610c69565b8281528092614ba9601f1991611c68565b0190602036910137565b15614bba57565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f7420757365203020617320746f6b656e20696e64657800000000006044820152606490fd5b15614c0657565b60405162461bcd60e51b815260206004820152601b60248201527f546f6b656e20686173206265656e206164646564206265666f726500000000006044820152606490fd5b15614c5257565b60405162461bcd60e51b8152602060048201526013602482015272125b99195e081a185cc81899595b881d5cd959606a1b6044820152606490fd5b15614c9457565b60405162461bcd60e51b815260206004820152602160248201527f436f726520746f6b656e207265717569726573206164646472657373283078316044820152602960f81b6064820152608490fd5b614cf160ff83161515614bb3565b6001600160a01b0381168015614da557612a439261073191614d34614d2e6105ed610ebb8760018060a01b03166000526066602052604060002090565b15614bff565b614d5a614d5461043d6115268560ff166000526065602052604060002090565b15614c4b565b614d6382614b41565b614d93575b506001600160a01b0383166000908152606660205260409020805460ff191660ff8316179055611f5a565b6001614d9f9114614c8d565b38614d68565b60405162461bcd60e51b815260206004820152601760248201527643616e6e6f7420757365207a65726f206164647265737360481b6044820152606490fdfee34b8b74e1cdcaa1b90aa77af7dd89e496ad9a4ae4a4d4759712101c7da2dce6360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca164736f6c6343000810000a000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2

Deployed Bytecode

0x608060405236156054577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f35b3d90fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e156050573d90f3fea164736f6c6343000810000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2

-----Decoded View---------------
Arg [0] : premiumManager (address): 0x666d6b8a44d226150ca9058bEEbafe0e3aC065A2

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000666d6b8a44d226150ca9058beebafe0e3ac065a2


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading

OVERVIEW

This is a contract on Arb

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x25aB3Efd52e6470681CE037cD546Dc60726948D3
Net Worth in USD
$3,153,601.31

Net Worth in M
MemeCore LogoMemeCore LogoMemeCore Logo 2,055,032.686964

Token Allocations
M 28.55%
MEME 20.58%
WBTC 8.62%
Others 42.26%
Chain Token Portfolio % Price Amount Value
BSC28.55%$1.54584,599.1726$900,282.73
BSC2.93%$68,129.691.3556$92,355.31
BSC2.45%$76,2841.0147$77,408.12
BSC1.51%$147,744.479$47,747.15
BSC1.22%$0.99991738,401.8016$38,398.61
BSC1.14%$0.060532594,231.9971$35,970.05
BSC0.87%$76,0430.3589$27,293.96
BSC0.42%$1.867,097.6692$13,230.44
BSC0.18%$0.9994435,705.8181$5,702.64
BSC0.08%$623.123.826$2,384.05
BSC0.04%$0.9985811,346.7658$1,344.85
BSC<0.01%$167.8102$67.82
BSC<0.01%$0.70000111$7.7
BSC<0.01%$0.00213300$0.6388
MEMECORE
Meme (MEME)
20.58%$1.54422,633.2644$648,937.78
MEMECORE0.10%$0.99993,097.8314$3,097.52
ETH7.05%$2,133.21104.1517$222,177.4
ETH2.89%$76,1491.1958$91,062.4
ETH1.93%$0.99987460,916.0602$60,908.38
ETH1.22%$0.99990338,487.3884$38,483.66
ETH1.17%$2,017.6118.3125$36,947.37
ETH0.36%$76,0430.1494$11,363.03
ETH0.28%$0.9994648,696.6276$8,691.97
ETH0.22%$0.999856,864.3905$6,863.36
ETH0.19%$0.06044799,081.7728$5,989.2
ETH0.19%$76,2120.0781$5,952.84
ETH0.19%$67,011.170.088$5,895.58
ETH0.18%$76,0770.0761$5,789.23
ETH0.01%$75,5570.005541$418.66
ETH0.01%$76,3400.004974$379.72
ETH<0.01%$11.890.0154$0.1833
ARB4.66%$76,1771.9286$146,917.32
ARB1.31%$2,017.2620.5384$41,431.35
ARB0.95%$0.99843830,162.9594$30,115.84
ARB0.95%$76,0430.3932$29,896.99
ARB0.78%$0.99990324,655.6011$24,653.21
ARB0.17%$0.0027412,000,000$5,481.05
ARB0.17%$76,2840.0692$5,276.41
ARB<0.01%$29.910.9907$29.63
ARB<0.01%$0.11368585.1747$9.68
BASE1.76%$76,0770.7296$55,505.93
BASE0.75%$0.99990323,596.4422$23,594.15
BASE0.74%$2,017.211.5804$23,359.97
BASE<0.01%$0.000234500$0.1172
AVAX0.80%$76,2840.3306$25,222.92
AVAX0.67%$76,0430.2765$21,027.94
AVAX0.65%$0.99958620,401.3877$20,392.94
AVAX0.55%$117,378.7558$17,379.73
OP1.26%$2,017.5619.7278$39,801.84
OP0.65%$0.9995520,653.1755$20,643.88
OP0.38%$0.99994811,836.8998$11,836.28
POL1.04%$76,1140.4328$32,944.96
POL0.66%$0.99829520,777.749$20,742.32
POL0.36%$0.99990311,216.5674$11,215.48
POL0.07%$0.11063721,310.6504$2,357.76
SEI0.60%$76,2750.2498$19,055.55
SEI0.17%$15,385.5828$5,385.88
SCROLL0.30%$2,017.614.7036$9,489.94
SCROLL0.15%$0.9994824,846.8847$4,844.37
SCROLL0.11%$0.9999483,544.3026$3,544.12
LINEA0.24%$0.9999487,486.312$7,485.92
LINEA0.23%$2,017.613.5826$7,228.28
LINEA0.10%$0.999553,116.9422$3,115.54
TAIKO0.35%$76,2120.1453$11,075.97
TAIKO0.09%$0.9971432,925.076$2,916.72
TAIKO0.03%$2,017.930.4564$920.96
TAIKO0.02%$76,1310.01$761.31
UNI0.23%$2,017.433.6185$7,300.09
UNI0.14%$0.9982954,494.2417$4,486.58
UNI0.12%$0.9999033,886.4388$3,886.06
OPBNB0.25%$623.1512.4161$7,737.03
OPBNB0.05%$0.9980171,673.2261$1,669.91
BLAST0.13%$0.9944644,129.0007$4,106.14
BLAST0.12%$2,017.261.8882$3,809.02
GLMR0.21%$16,651.3596$6,658.01
MANTLE0.12%$0.9940423,735.2162$3,712.96
MANTLE0.06%$11,987.3128$1,987.31
MANTLE<0.01%$0.6344310.00001301$0.000008
SONIC0.16%$0.99995,059.8389$5,059.33
SONIC<0.01%$0.048598856.7828$41.64
HYPEREVM0.16%$0.9988494,943.301$4,937.61
HYPEREVM<0.01%$29.482.5$73.7
PLASMA0.16%$0.9982954,902.1096$4,893.75
PLASMA<0.01%$0.09846733$3.25
BERA0.08%$1.012,607.2132$2,625.46
BERA0.05%$0.9983141,500$1,497.47
STABLE0.13%$0.9994193,947.6069$3,945.31
MONAD0.06%$0.9999031,805.8802$1,805.71
GNO0.05%$0.9998711,502.9555$1,502.76
CELO0.03%$0.9994731,048.0742$1,047.52
APE<0.01%$0.1278150.2406$0.030758
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.