ETH Price: $3,582.57 (-3.03%)

Contract

0xc9cED87b7073297cEB12453C0D65329D496fc0B4
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw To User212277112024-11-20 8:19:1112 days ago1732090751IN
0xc9cED87b...D496fc0B4
0 ETH0.000813878.2461642
Bridge212133682024-11-18 8:20:2314 days ago1731918023IN
0xc9cED87b...D496fc0B4
0 ETH0.0007947411.12178083
Bridge212129872024-11-18 7:03:4714 days ago1731913427IN
0xc9cED87b...D496fc0B4
0 ETH0.0009764113.6641957
Bridge212128972024-11-18 6:45:3514 days ago1731912335IN
0xc9cED87b...D496fc0B4
0 ETH0.00078711.80874267
Bridge212127052024-11-18 6:07:1114 days ago1731910031IN
0xc9cED87b...D496fc0B4
0 ETH0.0008772912.27914733
Bridge212125932024-11-18 5:44:4714 days ago1731908687IN
0xc9cED87b...D496fc0B4
0 ETH0.0007344410.27966067
Withdraw To User212114762024-11-18 2:00:5914 days ago1731895259IN
0xc9cED87b...D496fc0B4
0 ETH0.0012414510.72089441
Bridge212090682024-11-17 17:57:5914 days ago1731866279IN
0xc9cED87b...D496fc0B4
0 ETH0.0010170114.55954922
Bridge212089362024-11-17 17:31:3514 days ago1731864695IN
0xc9cED87b...D496fc0B4
0 ETH0.001225717.54713772
Bridge212086392024-11-17 16:31:5914 days ago1731861119IN
0xc9cED87b...D496fc0B4
0 ETH0.0009889814.16066492
Withdraw To User212085792024-11-17 16:19:3514 days ago1731860375IN
0xc9cED87b...D496fc0B4
0 ETH0.0012876111.11948354
Bridge212084642024-11-17 15:56:2314 days ago1731858983IN
0xc9cED87b...D496fc0B4
0 ETH0.0009217313.8277699
Withdraw To User212064852024-11-17 9:19:2315 days ago1731835163IN
0xc9cED87b...D496fc0B4
0 ETH0.000911498.61429735
Bridge212050362024-11-17 4:27:3515 days ago1731817655IN
0xc9cED87b...D496fc0B4
0 ETH0.000997649.89160284
Withdraw To User212040522024-11-17 1:10:1115 days ago1731805811IN
0xc9cED87b...D496fc0B4
0 ETH0.0027494210.10680241
Bridge212038772024-11-17 0:34:4715 days ago1731803687IN
0xc9cED87b...D496fc0B4
0 ETH0.0007257510.88767584
Bridge212038282024-11-17 0:24:5915 days ago1731803099IN
0xc9cED87b...D496fc0B4
0 ETH0.0011537411.43930385
Withdraw To User212016312024-11-16 17:04:1115 days ago1731776651IN
0xc9cED87b...D496fc0B4
0 ETH0.0039313114.04930281
Bridge Native211994912024-11-16 9:54:2316 days ago1731750863IN
0xc9cED87b...D496fc0B4
0.03508083 ETH0.0024638724.21214883
Withdraw To User211898062024-11-15 1:27:2317 days ago1731634043IN
0xc9cED87b...D496fc0B4
0 ETH0.0059018120.13411808
Withdraw To User211871942024-11-14 16:41:4717 days ago1731602507IN
0xc9cED87b...D496fc0B4
0 ETH0.0084809928.95179366
Withdraw To User211871572024-11-14 16:34:2317 days ago1731602063IN
0xc9cED87b...D496fc0B4
0 ETH0.00854229.14237536
Withdraw To User211871442024-11-14 16:31:4717 days ago1731601907IN
0xc9cED87b...D496fc0B4
0 ETH0.0098980633.76600738
Withdraw To User211870662024-11-14 16:16:1117 days ago1731600971IN
0xc9cED87b...D496fc0B4
0 ETH0.0104694534.44806231
Withdraw To User211870512024-11-14 16:13:1117 days ago1731600791IN
0xc9cED87b...D496fc0B4
0 ETH0.0117598539.21152791
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
212064852024-11-17 9:19:2315 days ago1731835163
0xc9cED87b...D496fc0B4
0.0246714 ETH
212064852024-11-17 9:19:2315 days ago1731835163
0xc9cED87b...D496fc0B4
0.0246714 ETH
211994912024-11-16 9:54:2316 days ago1731750863
0xc9cED87b...D496fc0B4
0.03508083 ETH
211870662024-11-14 16:16:1117 days ago1731600971
0xc9cED87b...D496fc0B4
0.0315 ETH
211870662024-11-14 16:16:1117 days ago1731600971
0xc9cED87b...D496fc0B4
0.0315 ETH
211870512024-11-14 16:13:1117 days ago1731600791
0xc9cED87b...D496fc0B4
0.051 ETH
211870512024-11-14 16:13:1117 days ago1731600791
0xc9cED87b...D496fc0B4
0.051 ETH
211557492024-11-10 7:23:4722 days ago1731223427
0xc9cED87b...D496fc0B4
0.00188674 ETH
211512042024-11-09 16:11:1122 days ago1731168671
0xc9cED87b...D496fc0B4
0.00014656 ETH
211499542024-11-09 11:59:2322 days ago1731153563
0xc9cED87b...D496fc0B4
0.0037798 ETH
211453142024-11-08 20:28:3523 days ago1731097715
0xc9cED87b...D496fc0B4
0.00319055 ETH
211453142024-11-08 20:28:3523 days ago1731097715
0xc9cED87b...D496fc0B4
0.00319055 ETH
211449202024-11-08 19:09:3523 days ago1731092975
0xc9cED87b...D496fc0B4
0.29648439 ETH
211449202024-11-08 19:09:3523 days ago1731092975
0xc9cED87b...D496fc0B4
0.29648439 ETH
211427982024-11-08 12:03:1123 days ago1731067391
0xc9cED87b...D496fc0B4
1.87011947 ETH
211427982024-11-08 12:03:1123 days ago1731067391
0xc9cED87b...D496fc0B4
1.87011947 ETH
211413052024-11-08 7:03:4724 days ago1731049427
0xc9cED87b...D496fc0B4
0.08774599 ETH
211413052024-11-08 7:03:4724 days ago1731049427
0xc9cED87b...D496fc0B4
0.08774599 ETH
211412952024-11-08 7:01:4724 days ago1731049307
0xc9cED87b...D496fc0B4
0.17052813 ETH
211412952024-11-08 7:01:4724 days ago1731049307
0xc9cED87b...D496fc0B4
0.17052813 ETH
211412782024-11-08 6:57:5924 days ago1731049079
0xc9cED87b...D496fc0B4
0.48 ETH
211412782024-11-08 6:57:5924 days ago1731049079
0xc9cED87b...D496fc0B4
0.48 ETH
211412032024-11-08 6:42:4724 days ago1731048167
0xc9cED87b...D496fc0B4
0.2282727 ETH
211412032024-11-08 6:42:4724 days ago1731048167
0xc9cED87b...D496fc0B4
0.2282727 ETH
211374412024-11-07 18:04:2324 days ago1731002663
0xc9cED87b...D496fc0B4
0.02635053 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MeldBridgeReceiver

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
shanghai EvmVersion
File 1 of 33 : MeldBridgeReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {MeldBridgeBase} from "./MeldBridgeBase.sol";
import {IMeldBridgeReceiver} from "./interfaces/IMeldBridgeReceiver.sol";
import {IBaseERC20} from "./interfaces/IBaseERC20.sol";
import {IBaseERC721} from "./interfaces/IBaseERC721.sol";
import {IBaseERC1155} from "./interfaces/IBaseERC1155.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {MeldFarmingManager} from "./MeldFarmingManager.sol";
import {Errors} from "./libraries/Errors.sol";

/**
 * @author  MELD team
 * @title   MeldBridgeReceiver
 * @notice  This contract is the receiver contract for the Meld Bridge. It is responsible for receiving tokens from the original network of the tokens and re-staking them
 */

contract MeldBridgeReceiver is IMeldBridgeReceiver, MeldBridgeBase {
    using SafeERC20 for IBaseERC20;

    address payable public override wETHAddress;

    bytes32 public constant override REBALANCER_ROLE = keccak256("REBALANCER_ROLE");

    MeldFarmingManager private farmingManager;

    /**
     * @notice Constructor
     * @param _defaultAdmin Address of the default admin
     * @param _wETH Address of the WETH contract
     * @param _treasury Address of the treasury
     */
    constructor(address _defaultAdmin, address _wETH, address _treasury) {
        _grantRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
        wETHAddress = payable(_wETH);
        emit WETHAddressSet(msg.sender, _wETH);
        farmingManager = new MeldFarmingManager(address(this), _treasury);
        emit MeldFarmingManagerDeployed(msg.sender, address(farmingManager));
    }

    /**
     * @notice Function to receive native tokens
     * @dev Only can receive from the WETH contract
     */
    receive() external payable {
        require(msg.sender == wETHAddress, Errors.MBR_ONLY_WETH_ALLOWED);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function bridge(
        address _token,
        uint256 _amount
    ) public override onlySupportedToken(_token) onlyPositiveAmount(_amount) {
        IBaseERC20(_token).safeTransferFrom(msg.sender, address(farmingManager), _amount);

        farmingManager.deposit(_token, _amount, "");

        emit BridgeRequested(msg.sender, _token, _amount);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function bridgeNative() public payable override {
        require(supportedTokens[address(0)], Errors.MBR_NATIVE_NOT_SUPPORTED);
        require(msg.value > 0, Errors.INVALID_AMOUNT);

        IWETH weth = IWETH(wETHAddress);

        uint256 wethBalanceBefore = weth.balanceOf(address(this));
        weth.deposit{value: msg.value}();
        require(
            weth.balanceOf(address(this)) == msg.value + wethBalanceBefore,
            Errors.MBR_NATIVE_WRAPPING_FAILED
        );
        IBaseERC20(wETHAddress).safeTransfer(address(farmingManager), msg.value);
        farmingManager.deposit(wETHAddress, msg.value, "");

        emit BridgeRequested(msg.sender, address(0), msg.value);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function bridgeERC721(
        address _token,
        uint256 _tokenId
    ) public override onlySupportedToken(_token) {
        IBaseERC721(_token).safeTransferFrom(msg.sender, address(this), _tokenId);

        emit BridgeERC721Requested(msg.sender, _token, _tokenId);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function bridgeERC1155(
        address _token,
        uint256 _tokenId,
        uint256 _amount
    ) public override onlySupportedToken(_token) onlyPositiveAmount(_amount) {
        IBaseERC1155(_token).safeTransferFrom(msg.sender, address(this), _tokenId, _amount, "");

        emit BridgeERC1155Requested(msg.sender, _token, _tokenId, _amount);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawToUser(
        address _token,
        address _to,
        uint256 _amount,
        bytes32 _requestID,
        bytes calldata _extra
    )
        public
        override
        onlyRole(EXECUTION_ROLE)
        onlySupportedToken(_token)
        onlyUnprocessedRequest(_requestID)
        onlyPositiveAmount(_amount)
    {
        if (_token == address(0)) {
            farmingManager.withdraw(wETHAddress, _amount, _extra);
            IBaseERC20(wETHAddress).safeTransferFrom(
                address(farmingManager),
                address(this),
                _amount
            );
            IWETH(wETHAddress).withdraw(_amount);
            payable(_to).transfer(_amount);
        } else {
            farmingManager.withdraw(_token, _amount, _extra);
            IBaseERC20(_token).safeTransferFrom(address(farmingManager), _to, _amount);
        }

        processedRequests[_requestID] = true;

        emit WithdrawnToUser(_token, _to, _amount, _requestID);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawERC721ToUser(
        address _token,
        address _to,
        uint256 _tokenId,
        bytes32 _requestID
    )
        public
        override
        onlyRole(EXECUTION_ROLE)
        onlySupportedToken(_token)
        onlyUnprocessedRequest(_requestID)
    {
        IBaseERC721(_token).safeTransferFrom(address(this), _to, _tokenId);

        processedRequests[_requestID] = true;

        emit WithdrawnERC721ToUser(_token, _to, _tokenId, _requestID);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawERC1155ToUser(
        address _token,
        address _to,
        uint256 _tokenId,
        uint256 _amount,
        bytes32 _requestID
    )
        public
        override
        onlyRole(EXECUTION_ROLE)
        onlySupportedToken(_token)
        onlyUnprocessedRequest(_requestID)
        onlyPositiveAmount(_amount)
    {
        IBaseERC1155(_token).safeTransferFrom(address(this), _to, _tokenId, _amount, "");

        processedRequests[_requestID] = true;

        emit WithdrawnERC1155ToUser(_token, _to, _tokenId, _amount, _requestID);
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawToUsers(
        address _token,
        address[] memory _tos,
        uint256[] memory _amounts,
        bytes32[] memory _requestIDs,
        bytes[] calldata _extra
    ) public override {
        require(
            _tos.length == _amounts.length &&
                _amounts.length == _requestIDs.length &&
                _requestIDs.length == _extra.length,
            Errors.INVALID_ARRAY_LENGTH
        );

        for (uint256 i = 0; i < _tos.length; i++) {
            withdrawToUser(_token, _tos[i], _amounts[i], _requestIDs[i], _extra[i]);
        }
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawERC721ToUsers(
        address _token,
        address[] memory _tos,
        uint256[] memory _tokenIds,
        bytes32[] memory _requestIDs
    ) public override {
        require(
            _tos.length == _tokenIds.length && _tokenIds.length == _requestIDs.length,
            Errors.INVALID_ARRAY_LENGTH
        );

        for (uint256 i = 0; i < _tos.length; i++) {
            withdrawERC721ToUser(_token, _tos[i], _tokenIds[i], _requestIDs[i]);
        }
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function withdrawERC1155ToUsers(
        address _token,
        address[] memory _tos,
        uint256[] memory _tokenIds,
        uint256[] memory _amounts,
        bytes32[] memory _requestIDs
    ) public override {
        require(
            _tos.length == _tokenIds.length &&
                _tokenIds.length == _requestIDs.length &&
                _tokenIds.length == _amounts.length,
            Errors.INVALID_ARRAY_LENGTH
        );

        for (uint256 i = 0; i < _tos.length; i++) {
            withdrawERC1155ToUser(_token, _tos[i], _tokenIds[i], _amounts[i], _requestIDs[i]);
        }
    }

    /**
     * @inheritdoc IMeldBridgeReceiver
     */
    function getFarmingManagerAddress() public view returns (address) {
        return address(farmingManager);
    }
}

File 2 of 33 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 3 of 33 : AccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}

File 4 of 33 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 5 of 33 : IAccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

File 6 of 33 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 7 of 33 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 8 of 33 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 9 of 33 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 10 of 33 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 11 of 33 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 12 of 33 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 13 of 33 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 14 of 33 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 15 of 33 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 16 of 33 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 17 of 33 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 18 of 33 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 19 of 33 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 20 of 33 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 21 of 33 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 22 of 33 : IBaseERC1155.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

/**
 * @title Base ERC1155 interface
 * @notice Interface for interacting with ERC1155 tokens with mint and burn functions
 * @author MELD team
 */
interface IBaseERC1155 is IERC1155 {
    /**
     * @notice Mint new tokens
     * @param _to Address to mint tokens to
     * @param _id Token ID to mint
     * @param _amount Amount of tokens to mint
     * @param _data Additional data
     */
    function mint(address _to, uint256 _id, uint256 _amount, bytes calldata _data) external;

    /**
     * @notice Burn tokens
     * @param _id Token ID to burn
     * @param _amount Amount of tokens to burn
     */
    function burn(uint256 _id, uint256 _amount) external;
}

File 23 of 33 : IBaseERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Base ERC20 interface
 * @notice Interface for interacting with ERC20 tokens with mint and burn functions
 * @author MELD team
 */
interface IBaseERC20 is IERC20 {
    /**
     * @notice Mint new tokens
     * @param _account Address to mint tokens to
     * @param _amount Amount of tokens to mint
     */
    function mint(address _account, uint256 _amount) external;

    /**
     * @notice Burn tokens
     * @param _amount Amount of tokens to burn
     */
    function burn(uint256 _amount) external;

    /**
     * @notice Get the number of decimals for the token
     * @return Number of decimals
     */
    function decimals() external view returns (uint8);
}

File 24 of 33 : IBaseERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
 * @title Base ERC721 interface
 * @notice Interface for interacting with ERC721 tokens with mint and burn functions
 * @author MELD team
 */
interface IBaseERC721 is IERC721 {
    /**
     * @notice Mint new tokens
     * @param _account Address to mint tokens to
     * @param _tokenId Token ID to mint
     */
    function mint(address _account, uint256 _tokenId) external;

    /**
     * @notice Burn tokens
     * @param _tokenId Token ID to burn
     */
    function burn(uint256 _tokenId) external;
}

File 25 of 33 : ILockedAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/**
 * @title Locked Adapter interface
 * @notice Interface for the locked adapters, to add the requestWithdraw function
 * @author MELD team
 */
interface ILockedAdapter {
    /**
     * @notice Request a withdraw from the adapter, so the funds can be withdrawn in the future
     * @param _asset Address of the asset to withdraw
     * @param _amount Amount to withdraw
     * @param _extra Extra data for the withdraw
     */
    function requestWithdraw(address _asset, uint256 _amount, bytes calldata _extra) external;
}

File 26 of 33 : IMeldBridgeBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/**
 * @title Meld Bridge Base interface
 * @notice Interface for the Meld Bridge Base contract, to set supported tokens and check roles
 * @author MELD team
 */
interface IMeldBridgeBase {
    /**
     * @notice Emitted when a token is supported or unsupported
     * @param executedBy Address that executed the event
     * @param token Address of the token
     * @param supported True if the token is supported, false if unsupported
     */
    event SupportedTokenSet(address indexed executedBy, address indexed token, bool supported);

    /**
     * @notice Set the supported status of a token
     * @param _token Address of the token
     * @param _supported True if the token is supported, false if unsupported
     */
    function setSupportedToken(address _token, bool _supported) external;

    /**
     * @notice Check if an account has a role. Reverts if the account does not have the role
     * @param _role Role to check
     * @param _account Account to check
     */
    function checkRole(bytes32 _role, address _account) external view;

    /**
     * @notice Role for configuration
     * @return Role
     */
    function CONFIGURATION_ROLE() external view returns (bytes32); // solhint-disable-line func-name-mixedcase

    /**
     * @notice Role for execution of requests
     * @return Role
     */
    function EXECUTION_ROLE() external view returns (bytes32); // solhint-disable-line func-name-mixedcase

    /**
     * @notice Check if a token is supported
     * @param _token Address of the token
     * @return True if the token is supported
     */
    function supportedTokens(address _token) external view returns (bool);

    /**
     * @notice Check if a request has been processed
     * @param _requestId ID of the request
     * @return True if the request has been processed
     */
    function processedRequests(bytes32 _requestId) external view returns (bool);
}

File 27 of 33 : IMeldBridgeReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IMeldBridgeBase} from "./IMeldBridgeBase.sol";

/**
 * @title Meld Bridge Receiver interface
 * @notice Interface for interacting with the Meld Bridge Receiver contract
 * @author MELD team
 */
interface IMeldBridgeReceiver is IMeldBridgeBase {
    /**
     * @notice Event emitted when a user requests to bridge tokens
     * @param user Address of the user
     * @param token Address of the token
     * @param amount Amount of tokens to bridge
     */
    event BridgeRequested(address indexed user, address indexed token, uint256 amount);

    /**
     * @notice Event emitted when the wETH address is set
     * @param executedBy Address that executed the action
     * @param wETH Address of the wETH contract
     */
    event WETHAddressSet(address indexed executedBy, address indexed wETH);

    /**
     * @notice Event emitted when the Meld Farming Manager is deployed
     * @param executedBy Address that executed the action
     * @param meldFarmingManagerAddress Address of the Meld Farming Manager
     */
    event MeldFarmingManagerDeployed(
        address indexed executedBy,
        address indexed meldFarmingManagerAddress
    );

    /**
     * @notice Event emitted when a user requests to bridge ERC721 tokens
     * @param user Address of the user
     * @param token Address of the token
     * @param tokenId Token ID to bridge
     */
    event BridgeERC721Requested(address indexed user, address indexed token, uint256 tokenId);

    /**
     * @notice Event emitted when a user requests to bridge ERC1155 tokens
     * @param user Address of the user
     * @param token Address of the token
     * @param tokenId Token ID to bridge
     * @param amount Amount of tokens to bridge
     */
    event BridgeERC1155Requested(
        address indexed user,
        address indexed token,
        uint256 tokenId,
        uint256 amount
    );

    /**
     * @notice Event emitted when ERC20 tokens are withdrawn to a user
     * @param token Address of the token
     * @param to Address of the user
     * @param amount Amount of tokens withdrawn
     * @param requestID ID of the request
     */
    event WithdrawnToUser(
        address indexed token,
        address indexed to,
        uint256 amount,
        bytes32 indexed requestID
    );

    /**
     * @notice Event emitted when ERC721 tokens are withdrawn to a user
     * @param token Address of the token
     * @param to Address of the user
     * @param tokenId Token ID withdrawn
     * @param requestID ID of the request
     */
    event WithdrawnERC721ToUser(
        address indexed token,
        address indexed to,
        uint256 tokenId,
        bytes32 indexed requestID
    );

    /**
     * @notice Event emitted when ERC1155 tokens are withdrawn to a user
     * @param token Address of the token
     * @param to Address of the user
     * @param tokenId Token ID withdrawn
     * @param amount Amount of tokens withdrawn
     * @param requestID ID of the request
     */
    event WithdrawnERC1155ToUser(
        address indexed token,
        address indexed to,
        uint256 tokenId,
        uint256 amount,
        bytes32 indexed requestID
    );

    /**
     * @notice Function called to bridge ERC20 tokens
     * @param _token Address of the token
     * @param _amount Amount of tokens to bridge
     */
    function bridge(address _token, uint256 _amount) external;

    /**
     * @notice Function called to bridge native tokens
     * @dev This function is payable so the amount of tokens to bridge is the value sent with the transaction
     */
    function bridgeNative() external payable;

    /**
     * @notice Function called to bridge ERC721 tokens
     * @param _token Address of the token
     * @param _tokenId Token ID to bridge
     */
    function bridgeERC721(address _token, uint256 _tokenId) external;

    /**
     * @notice Function called to bridge ERC1155 tokens
     * @param _token Address of the token
     * @param _tokenId Token ID to bridge
     * @param _amount Amount of tokens to bridge
     */
    function bridgeERC1155(address _token, uint256 _tokenId, uint256 _amount) external;

    /**
     * @notice Function called to withdraw tokens to a user
     * @param _token Address of the token
     * @param _to Address of the user
     * @param _amount Amount of tokens to withdraw
     * @param _requestID ID of the request
     * @param _extra Additional data
     */
    function withdrawToUser(
        address _token,
        address _to,
        uint256 _amount,
        bytes32 _requestID,
        bytes calldata _extra
    ) external;

    /**
     * @notice Function called to withdraw ERC721 tokens to a user
     * @param _token Address of the token
     * @param _to Address of the user
     * @param _tokenId Token ID to withdraw
     * @param _requestID ID of the request
     */
    function withdrawERC721ToUser(
        address _token,
        address _to,
        uint256 _tokenId,
        bytes32 _requestID
    ) external;

    /**
     * @notice Function called to withdraw ERC1155 tokens to a user
     * @param _token Address of the token
     * @param _to Address of the user
     * @param _tokenId Token ID to withdraw
     * @param _amount Amount of tokens to withdraw
     * @param _requestID ID of the request
     */
    function withdrawERC1155ToUser(
        address _token,
        address _to,
        uint256 _tokenId,
        uint256 _amount,
        bytes32 _requestID
    ) external;

    /**
     * @notice Function called to withdraw tokens to multiple users
     * @param _token Address of the token
     * @param _to Addresses of the users
     * @param _amount Amounts of tokens to withdraw
     * @param _requestID IDs of the requests
     * @param _extra Additional data
     */
    function withdrawToUsers(
        address _token,
        address[] calldata _to,
        uint256[] calldata _amount,
        bytes32[] calldata _requestID,
        bytes[] calldata _extra
    ) external;

    /**
     * @notice Function called to withdraw ERC721 tokens to multiple users
     * @param _token Address of the token
     * @param _to Addresses of the users
     * @param _tokenId Token IDs to withdraw
     * @param _requestID IDs of the requests
     */
    function withdrawERC721ToUsers(
        address _token,
        address[] calldata _to,
        uint256[] calldata _tokenId,
        bytes32[] calldata _requestID
    ) external;

    /**
     * @notice Function called to withdraw ERC1155 tokens to multiple users
     * @param _token Address of the token
     * @param _to Addresses of the users
     * @param _tokenId Token IDs to withdraw
     * @param _amount Amounts of tokens to withdraw
     * @param _requestID IDs of the requests
     */
    function withdrawERC1155ToUsers(
        address _token,
        address[] calldata _to,
        uint256[] calldata _tokenId,
        uint256[] calldata _amount,
        bytes32[] calldata _requestID
    ) external;

    /**
     * @notice Returns the bytes32 identifier for the REBALANCER_ROLE
     */
    function REBALANCER_ROLE() external view returns (bytes32); // solhint-disable-line func-name-mixedcase

    /**
     * @notice Returns the address of the wETH contract
     */
    function wETHAddress() external view returns (address payable);

    /**
     * @notice Returns the address of the Meld Farming Manager
     */
    function getFarmingManagerAddress() external view returns (address);
}

File 28 of 33 : IMeldFarming.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @title Meld Farming interface
 * @notice Interface for the Meld Farming Manager contract as well as the adapters
 * @author MELD team
 */
interface IMeldFarming is IERC165 {
    /**
     * @notice Emitted when an asset is deposited
     * @param asset Address of the asset
     * @param amount Amount deposited
     */
    event Deposited(address indexed asset, uint256 amount);

    /**
     * @notice Emitted when an asset is withdrawn
     * @param asset Address of the asset
     * @param amount Amount withdrawn
     */
    event Withdrawn(address indexed asset, uint256 amount);

    /**
     * @notice Deposits funds into the Meld Farming Manager or the adapter
     * @param _asset Address of the asset to deposit
     * @param _amount Amount to deposit
     * @param _extra Extra data for the deposit
     */
    function deposit(address _asset, uint256 _amount, bytes calldata _extra) external;

    /**
     * @notice Withdraws funds from the Meld Farming Manager or the adapter
     * @param _asset Address of the asset to withdraw
     * @param _amount Amount to withdraw
     * @param _extra Extra data for the withdraw
     * @return Amount withdrawn
     */
    function withdraw(
        address _asset,
        uint256 _amount,
        bytes calldata _extra
    ) external returns (uint256);

    /**
     * @notice Claims rewards from the adapter
     * @param _asset Address of the asset to claim
     * @param _extra Extra data for the claim
     * @param _withdrawOnlyAvailable If true, only claims the rewards up to the available liquidity. If false and there's not enough liquidity, it reverts
     * @return Amount claimed
     */
    function claimRewards(
        address _asset,
        bytes calldata _extra,
        bool _withdrawOnlyAvailable
    ) external returns (uint256);

    /**
     * @notice Returns the total available liquidity for a given asset
     * @param _asset Address of the asset
     * @return Available liquidity
     */
    function getAvailableLiquidity(address _asset) external view returns (uint256);

    /**
     * @notice Returns the amount of rewards available for the `_asset`
     * @param _asset Address of the asset
     * @return Amount of rewards available
     */
    function getRewardsAmount(address _asset) external view returns (uint256);

    /**
     * @notice Returns the address of the Meld Farming Manager
     * @return Address of the Meld Farming Manager
     */
    function meldFarmingManager() external view returns (address);
}

File 29 of 33 : IMeldFarmingManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IMeldFarming} from "./IMeldFarming.sol";
import {IMeldBridgeReceiver} from "./IMeldBridgeReceiver.sol";

/**
 * @title Meld Farming Manager interface
 * @notice Interface for the Meld Farming Manager contract
 * @dev This interface also includes the IMeldFarming interface
 * @author MELD team
 */
interface IMeldFarmingManager is IMeldFarming {
    struct AdapterConfig {
        string adapterIdStr;
        bool enabled;
        bool locked;
        bool exists;
    }

    struct YieldAssetAdapter {
        uint256 yieldDeposit;
        uint256 index;
        uint256 lastTimestampRewardsClaimed;
        bool exists;
    }

    struct YieldAssetConfig {
        uint256 liquidDeposit;
        mapping(uint256 index => address adapterAddress) adapterIndex;
        mapping(address adapterAddress => YieldAssetAdapter) adapters;
        uint256 numAdapters;
    }

    struct RebalancingInfo {
        address asset;
        address adapterAddress;
        uint256 amount;
        RebalanceAction action;
        bytes extra;
    }

    enum RebalanceAction {
        NONE,
        DEPOSIT,
        WITHDRAW,
        REQUEST_WITHDRAW
    }

    /**
     * @notice Emitted when the Meld Bridge Receiver contract is set
     * @param bridge Address of the Meld Bridge Receiver contract
     */
    event BridgeSet(address indexed executedBy, address bridge);

    /**
     * @notice Emitted when the treasury address is updated
     * @param executedBy Address that executed the function
     * @param oldTreasury Address of the old treasury
     * @param newTreasury Address of the new treasury
     */
    event TreasuryUpdated(
        address indexed executedBy,
        address indexed oldTreasury,
        address indexed newTreasury
    );

    /**
     * @notice Emitted when a new adapter is added
     * @param executedBy Address that executed the function
     * @param adapterIdStr String ID of the adapter
     * @param adapterAddress Address of the adapter
     * @param locked Boolean indicating if the adapter is locked
     */
    event AdapterAdded(
        address executedBy,
        string indexed adapterIdStr,
        address indexed adapterAddress,
        bool locked
    );

    /**
     * @notice Emitted when an adapter is enabled or disabled
     * @param executedBy Address that executed the function
     * @param adapterAddress Address of the adapter
     * @param enabled Boolean indicating if the adapter is enabled
     */
    event AdapterEnabled(address indexed executedBy, address indexed adapterAddress, bool enabled);

    /**
     * @notice Emitted when an asset is configured with adapters
     * @param executedBy Address that executed the function
     * @param asset Address of the asset
     * @param adapterAddresses Array of adapter addresses
     */
    event AssetConfigSet(
        address indexed executedBy,
        address indexed asset,
        address[] adapterAddresses
    );

    /**
     * @notice Emitted when rewards are claimed
     * @param executedBy Address that executed the function
     * @param asset Address of the asset
     * @param adapterAddress Address of the adapter
     * @param amount Amount claimed
     */
    event RewardsClaimed(
        address indexed executedBy,
        address indexed asset,
        address indexed adapterAddress,
        uint256 amount
    );

    /**
     * @notice Emitted when a rebalance is executed
     * @param executedBy Address that executed the function
     * @param asset Address of the asset
     * @param adapterAddress Address of the adapter
     * @param amount Amount rebalanced
     * @param action Rebalance action. 0: None, 1: Deposit, 2: Withdraw, 3: Request Withdraw
     */
    event Rebalanced(
        address executedBy,
        address indexed asset,
        address indexed adapterAddress,
        uint256 amount,
        RebalanceAction indexed action
    );

    /**
     * @notice Adds a new adapter to the Meld Farming Manager
     * @param _adapterId String ID of the adapter
     * @param _adapterAddress Address of the adapter
     * @param _locked Boolean indicating if the adapter is locked
     */
    function addAdapter(string memory _adapterId, address _adapterAddress, bool _locked) external;

    /**
     * @notice Enables or disables an adapter
     * @param _adapterAddress Address of the adapter
     * @param _enabled Boolean indicating if the adapter is enabled
     */
    function setAdapterEnabled(address _adapterAddress, bool _enabled) external;

    /**
     * @notice Configures an asset with adapters
     * @dev The list of adapters will be the new one, so any previous configuration will be overwritten
     * @dev To remove all adapters, pass an empty array
     * @dev It is needed to call this function even if no adapters will be used for the asset
     * @param _asset Address of the asset
     * @param _adaptersAddresses Array of adapter addresses
     */
    function configAsset(address _asset, address[] memory _adaptersAddresses) external;

    /**
     * @notice Sets the treasury address that will receive the rewards
     * @param _treasury Address of the treasury
     */
    function setTreasury(address _treasury) external;

    /**
     * @notice Moves funds between the adapters and the Meld Farming Manager
     * @param _rebalanceInfo Array of RebalancingInfo, indicating the asset, adapter, amount and action
     */
    function rebalance(RebalancingInfo[] calldata _rebalanceInfo) external;

    /**
     * @notice Returns the adapter address for a given index
     * @param _index Index of the adapter
     * @return Adapter address
     */
    function adapterAddresses(uint256 _index) external view returns (address);

    /**
     * @notice Returns the number of adapters
     * @return Number of adapters
     */
    function numAdapters() external view returns (uint256);

    /**
     * @notice Returns the Meld Bridge Receiver contract address
     * @return Meld Bridge Receiver contract address
     */
    function bridge() external view returns (IMeldBridgeReceiver);

    /**
     * @notice Returns the treasury address
     * @return Treasury address
     */
    function treasury() external view returns (address);

    /**
     * @notice Returns the adapter configuration for a given ID
     * @param _adapterAddress Address of the adapter
     * @return Adapter configuration
     */
    function getAdapter(address _adapterAddress) external view returns (AdapterConfig memory);

    /**
     * @notice Returns the adapter configuration for all adapters
     * @return Array of every Adapter configuration
     */
    function getAllAdapters() external view returns (AdapterConfig[] memory);

    /**
     * @notice Returns the asset configuration for a given asset
     * @param _asset Address of the asset
     * @return assetAdapterIds Array of the adapter IDs for each adapter
     * @return assetAdapterAddressess Array of the adapter addresses for each adapter
     * @return yieldDeposit Array of the yield deposit for each adapter
     * @return lastTimestampRewardsClaimed Array of the last timestamp rewards claimed for each adapter
     * @return liquidDeposit Liquid deposit for the asset
     * @return totalDeposit Total deposit for the asset
     * @return totalAvailableLiquidity Total available liquidity for the asset
     */
    function getYieldAssetConfig(
        address _asset
    )
        external
        view
        returns (
            string[] memory assetAdapterIds,
            address[] memory assetAdapterAddressess,
            uint256[] memory yieldDeposit,
            uint256[] memory lastTimestampRewardsClaimed,
            uint256 liquidDeposit,
            uint256 totalDeposit,
            uint256 totalAvailableLiquidity
        );

    /**
     * @notice Returns the total deposit for a given asset
     * @param _asset Address of the asset
     * @return Total deposit
     */
    function getTotalDeposit(address _asset) external view returns (uint256);
}

File 30 of 33 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @title Wrapped AVAX/ETH interface
 * @notice Interface for interacting with the Wrapped AVAX/ETH token
 * @dev This interface is used to interact with the Wrapped AVAX/ETH token
 * @author MELD team
 */
interface IWETH is IERC20Metadata {
    /**
     * @notice Emmited when ETH is deposited to receive WETH
     * @param dst Address that receives the WETH
     * @param wad Amount of ETH deposited
     */
    event Deposit(address indexed dst, uint wad);

    /**
     * @notice Emmited when ETH is withdrawn
     * @param src Address that withdraws the ETH
     * @param wad Amount of ETH withdrawn
     */
    event Withdrawal(address indexed src, uint wad);

    /**
     * @notice Deposit ETH to receive WETH
     * @dev This function is payable so the amount of ETH deposited is the value sent with the transaction
     */
    function deposit() external payable;

    /**
     * @notice Withdraw ETH burning WETH
     * @param _wad Amount of ETH to withdraw
     */
    function withdraw(uint256 _wad) external;
}

File 31 of 33 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/**
 * @title Errors library
 * @notice Defines the error messages emitted by the different contracts of the Meld Bridge
 * @dev Error messages prefix glossary:
 * - MBP: Meld Bridge Panoptic
 * - MBR: Meld Bridge Receiver
 * - MFM: Meld Farming Manager
 * - BYA: Base Yield Adapter
 * @author MELD team
 */
library Errors {
    string public constant INVALID_ARRAY_LENGTH = "Invalid array length";
    string public constant TOKEN_NOT_SUPPORTED = "Token is not supported";
    string public constant REQUEST_ALREADY_PROCESSED = "Request already processed";
    string public constant INVALID_ADDRESS = "Invalid address";
    string public constant INVALID_AMOUNT = "Invalid amount";

    string public constant MBP_REQUEST_NOT_PROCESSED = "MeldBridgePanoptic: Request not processed";
    string public constant MBP_NETWORK_NOT_SUPPORTED =
        "MeldBridgePanoptic: Network is not supported for this token";
    string public constant MBP_INSUFFICIENT_FEE = "MeldBridgePanoptic: Insufficient fee";
    string public constant MBP_TRANSFERRING_FEE_FAILED =
        "MeldBridgePanoptic: Transferring fee failed";
    string public constant MBP_SIGNATURE_EXPIRED = "MeldBridgePanoptic: Signature is expired";

    string public constant MBR_ONLY_WETH_ALLOWED =
        "MeldBridgeReceiver: Only WETH can deposit ETH directly to the contract";
    string public constant MBR_NATIVE_NOT_SUPPORTED =
        "MeldBridgeReceiver: Native Token is not supported";
    string public constant MBR_NATIVE_WRAPPING_FAILED =
        "MeldBridgeReceiver: Native wrapping failed";
    string public constant MBR_NATIVE_TOKEN_NOT_WETH =
        "MeldBridgeReceiver: Native token withdraw is not WETH";

    string public constant MFM_ONLY_BRIDGE_ALLOWED =
        "MeldFarmingManager: Only bridge can call this function";
    string public constant MFM_ADAPTER_ALREADY_EXISTS =
        "MeldFarmingManager: Adapter already exists";
    string public constant MFM_ADAPTER_ADDRESS_ALREADY_EXISTS =
        "MeldFarmingManager: Adapter address already exists";
    string public constant MFM_ADAPTER_DOES_NOT_EXIST =
        "MeldFarmingManager: Adapter does not exist";
    string public constant MFM_ADAPTER_DISABLED = "MeldFarmingManager: Adapter is disabled";
    string public constant MFM_AMOUNT_MISMATCH = "MeldFarmingManager: Amount mismatch";
    string public constant MFM_NOT_ENOUGH_FUNDS = "MeldFarmingManager: Not enough funds";
    string public constant MFM_INVALID_ADAPTER_ID = "MeldFarmingManager: Invalid adapter ID";
    string public constant MFM_NO_ADAPTERS_CONFIGURED =
        "MeldFarmingManager: No adapters configured";
    string public constant MFM_INVALID_ADAPTER_MFM =
        "MeldFarmingManager: Invalid adapter MeldFarmingManager address";
    string public constant MFM_ADAPTER_IS_NOT_MELD_FARMING =
        "MeldFarmingManager: Adapter does not implement IMeldFarming";

    string public constant RT_NO_TOKENS_TO_RESCUE = "RescueTokens: No tokens to rescue";
    string public constant RT_RESCUER_NOT_OWNER =
        "RescueTokens: Contract is not the owner of the token";

    string public constant BYA_ONLY_FARMING_MANAGER_ALLOWED =
        "BaseYieldAdapter: Only MeldFarmingManager can call this function";

    string public constant AAVE_ADAPTER_INCONSISTENT_ATOKEN_BALANCE =
        "AaveAdapter: Inconsistent aToken balance";
    string public constant AAVE_ADAPTER_INVALID_WITHDRAWN_AMOUNT =
        "AaveAdapter: Invalid withdrawn amount";

    string public constant GOGOPOOL_ONLY_WAVAX_ALLOWED = "GoGoPoolAdapter: Only WAVAX is allowed";
    string public constant GOGOPOOL_AVAX_RECEIVED_OUTSIDE_WINDOW =
        "GoGoPoolAdapter: AVAX received outside window";
}

File 32 of 33 : MeldBridgeBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {AccessControlEnumerable} from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {
    IERC1155Receiver,
    IERC165
} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IMeldBridgeBase} from "./interfaces/IMeldBridgeBase.sol";
import {Errors} from "./libraries/Errors.sol";

/**
 * @title MeldBridgeBase
 * @notice This contract is the base contract for the MeldBridgePanoptic and MeldBridgeReceiver contracts
 * @dev Handles the supported tokens and roles
 * @author MELD team
 */
contract MeldBridgeBase is
    AccessControlEnumerable,
    IMeldBridgeBase,
    IERC721Receiver,
    IERC1155Receiver
{
    bytes32 public constant override CONFIGURATION_ROLE = keccak256("CONFIGURATION_ROLE");
    bytes32 public constant override EXECUTION_ROLE = keccak256("EXECUTION_ROLE");

    // mapping for supported tokens
    mapping(address => bool) public override supportedTokens;

    // mapping for processed requests
    mapping(bytes32 requestID => bool processed) public override processedRequests;

    /**
     * @notice  Modifier to check if the token is supported
     * @param _token Address of the token
     */
    modifier onlySupportedToken(address _token) {
        require(supportedTokens[_token], Errors.TOKEN_NOT_SUPPORTED);
        _;
    }

    /**
     * @notice  Modifier to check if the request has not been processed
     * @param _requestID ID of the request
     */
    modifier onlyUnprocessedRequest(bytes32 _requestID) {
        require(!processedRequests[_requestID], Errors.REQUEST_ALREADY_PROCESSED);
        _;
    }

    /**
     * @notice  Modifier to check if the amount is positive
     * @param _amount Amount to check
     */
    modifier onlyPositiveAmount(uint256 _amount) {
        require(_amount > 0, Errors.INVALID_AMOUNT);
        _;
    }

    /**
     * @inheritdoc IMeldBridgeBase
     */
    function setSupportedToken(
        address _token,
        bool _supported
    ) external override onlyRole(CONFIGURATION_ROLE) {
        supportedTokens[_token] = _supported;

        emit SupportedTokenSet(msg.sender, _token, _supported);
    }

    /**
     * @inheritdoc IMeldBridgeBase
     */
    function checkRole(bytes32 _role, address _account) external view override {
        return _checkRole(_role, _account);
    }

    /**
     * @inheritdoc IERC165
     */
    function supportsInterface(
        bytes4 _interfaceId
    ) public view override(AccessControlEnumerable, IERC165) returns (bool) {
        return
            _interfaceId == type(IERC1155Receiver).interfaceId ||
            super.supportsInterface(_interfaceId);
    }

    /**
     * @inheritdoc IERC721Receiver
     */
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) public pure override returns (bytes4) {
        return this.onERC721Received.selector;
    }

    /**
     * @inheritdoc IERC1155Receiver
     */
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) public pure override returns (bytes4) {
        return this.onERC1155Received.selector;
    }

    /**
     * @inheritdoc IERC1155Receiver
     */
    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) public pure override returns (bytes4) {
        return this.onERC1155BatchReceived.selector;
    }
}

File 33 of 33 : MeldFarmingManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IMeldFarming, IMeldFarmingManager} from "./interfaces/IMeldFarmingManager.sol";
import {ILockedAdapter} from "./interfaces/ILockedAdapter.sol";
import {IMeldBridgeReceiver} from "./interfaces/IMeldBridgeReceiver.sol";
import {Errors} from "./libraries/Errors.sol";

/**
 * @title Meld Farming Manager contract
 * @notice Contract that manages the yield farming adapters
 * @author MELD team
 */
contract MeldFarmingManager is IMeldFarmingManager {
    using SafeERC20 for IERC20;

    mapping(uint256 index => address adapterAddress) public override adapterAddresses;
    mapping(address adapterAddress => AdapterConfig config) private adapters;
    uint256 public override numAdapters;

    mapping(address => YieldAssetConfig) private yieldAssetConfigs;

    IMeldBridgeReceiver public override bridge;
    address public override treasury;

    /**
     * @notice Modifier to check that only the bridge can call the function
     */
    modifier onlyBridge() {
        require(msg.sender == address(bridge), Errors.MFM_ONLY_BRIDGE_ALLOWED);
        _;
    }

    /**
     * @notice Modifier to check that the caller has the required role
     * @dev It queries the bridge contract to check the role
     * @param _role Role required to call the function
     */
    modifier onlyRole(bytes32 _role) {
        bridge.checkRole(_role, msg.sender);
        _;
    }

    /**
     * @notice Constructor of the contract
     * @param _bridge Address of the Meld Bridge Receiver contract
     * @param _treasury Address of the treasury
     */
    constructor(address _bridge, address _treasury) {
        bridge = IMeldBridgeReceiver(_bridge);
        emit BridgeSet(msg.sender, _bridge);
        _setTreasury(_treasury);
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function addAdapter(
        string memory _adapterId,
        address _adapterAddress,
        bool _locked
    ) external override onlyRole(bridge.CONFIGURATION_ROLE()) {
        require(bytes(_adapterId).length > 0, Errors.MFM_INVALID_ADAPTER_ID);
        require(!adapters[_adapterAddress].exists, Errors.MFM_ADAPTER_ALREADY_EXISTS);
        require(_adapterAddress != address(0), Errors.INVALID_ADDRESS);
        IMeldFarming adapter = IMeldFarming(_adapterAddress);
        require(
            adapter.supportsInterface(type(IMeldFarming).interfaceId),
            Errors.MFM_ADAPTER_IS_NOT_MELD_FARMING
        );
        require(adapter.meldFarmingManager() == address(this), Errors.MFM_INVALID_ADAPTER_MFM);

        adapters[_adapterAddress] = AdapterConfig({
            adapterIdStr: _adapterId,
            enabled: true,
            locked: _locked,
            exists: true
        });
        adapterAddresses[numAdapters] = _adapterAddress;
        numAdapters++;
        emit AdapterAdded(msg.sender, _adapterId, _adapterAddress, _locked);
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function setAdapterEnabled(
        address _adapterAddress,
        bool _enabled
    ) external override onlyRole(bridge.CONFIGURATION_ROLE()) {
        AdapterConfig storage adapter = adapters[_adapterAddress];
        require(adapter.exists, Errors.MFM_ADAPTER_DOES_NOT_EXIST);
        adapter.enabled = _enabled;
        emit AdapterEnabled(msg.sender, _adapterAddress, _enabled);
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function configAsset(
        address _asset,
        address[] memory _adaptersAddresses
    ) external override onlyRole(bridge.CONFIGURATION_ROLE()) {
        YieldAssetConfig storage yaConfig = yieldAssetConfigs[_asset];

        address[] memory tempAdapterAddresses = new address[](
            yaConfig.numAdapters + _adaptersAddresses.length
        );
        address tempAdapterAddress;
        YieldAssetAdapter memory tempAdapter;
        uint256 tempNumAdapters = yaConfig.numAdapters;

        _safeApproveAll(IERC20(_asset), address(bridge));

        // We create an array of size oldList + newList of adapter ids
        // If the adapter already exists, we set its id in the same position
        // If the adapter doesn't exist, we set its id after the last position of the old list and update that pointer
        // Once that it's done, we have to reorganize the info to remove the empty spaces

        for (uint256 i = 0; i < _adaptersAddresses.length; i++) {
            require(adapters[_adaptersAddresses[i]].exists, Errors.MFM_ADAPTER_DOES_NOT_EXIST);
            // Iterate over the new list of adapters
            tempAdapterAddress = _adaptersAddresses[i];
            tempAdapter = yaConfig.adapters[tempAdapterAddress];
            if (tempAdapter.exists) {
                // If the adapter already exists, set its id in the tempAdapterAddresss
                tempAdapterAddresses[tempAdapter.index] = tempAdapterAddress;
            } else {
                // If the adapter doesn't exist, add it to the list
                tempAdapterAddresses[tempNumAdapters] = tempAdapterAddress;
                yaConfig.adapterIndex[tempNumAdapters] = tempAdapterAddress;
                yaConfig.adapters[tempAdapterAddress] = YieldAssetAdapter({
                    yieldDeposit: 0,
                    lastTimestampRewardsClaimed: 0,
                    index: tempNumAdapters,
                    exists: true
                });

                _safeApproveAll(IERC20(_asset), tempAdapterAddress);
                tempNumAdapters++;
            }
        }

        emit AssetConfigSet(msg.sender, _asset, _adaptersAddresses);
        if (tempNumAdapters == 0) {
            return;
        }

        uint256 rewardsClaimed = 0;
        uint256 tempRewards;

        for (uint256 i = 0; i < yaConfig.numAdapters; i++) {
            if (tempAdapterAddresses[i] != address(0)) {
                // Position not empty
                continue;
            }
            // Position empty

            // Withdraw all from the adapter

            address oldAdapterAddress = adapterAddresses[i];

            AdapterConfig memory adapterConfig = adapters[oldAdapterAddress];

            _checkAdapterEnabled(adapterConfig);

            uint256 adapterAssetDepositAmount = yaConfig.adapters[oldAdapterAddress].yieldDeposit;

            yaConfig.liquidDeposit += IMeldFarming(oldAdapterAddress).withdraw(
                _asset,
                adapterAssetDepositAmount,
                ""
            );
            tempRewards = IMeldFarming(oldAdapterAddress).claimRewards(_asset, "", false);
            rewardsClaimed += tempRewards;
            emit RewardsClaimed(msg.sender, _asset, oldAdapterAddress, tempRewards);

            // Remove old position
            delete yaConfig.adapters[oldAdapterAddress];
            for (; tempNumAdapters > i; tempNumAdapters--) {
                if (tempAdapterAddresses[tempNumAdapters - 1] == address(0)) {
                    // Last position empty
                    continue;
                }
                tempAdapterAddresses[i] = tempAdapterAddresses[tempNumAdapters - 1];
                yaConfig.adapters[tempAdapterAddresses[i]].index = i;
                yaConfig.adapterIndex[i] = tempAdapterAddresses[i];
                tempAdapterAddresses[tempNumAdapters - 1] = address(0);
                tempNumAdapters--;
                break;
            }
        }

        yaConfig.numAdapters = _adaptersAddresses.length;

        if (rewardsClaimed > 0) {
            IERC20(_asset).safeTransfer(treasury, rewardsClaimed);
        }
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function setTreasury(
        address _treasury
    ) external override onlyRole(bridge.CONFIGURATION_ROLE()) {
        _setTreasury(_treasury);
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function rebalance(
        RebalancingInfo[] calldata _rebalanceInfo
    ) external override onlyRole(bridge.REBALANCER_ROLE()) {
        require(_rebalanceInfo.length > 0, Errors.INVALID_ARRAY_LENGTH);
        for (uint256 i = 0; i < _rebalanceInfo.length; i++) {
            RebalancingInfo calldata rebalanceInfo = _rebalanceInfo[i];
            _checkAdapterEnabled(adapters[rebalanceInfo.adapterAddress]);
            IMeldFarming adapter = IMeldFarming(rebalanceInfo.adapterAddress);

            YieldAssetConfig storage yaConfig = yieldAssetConfigs[rebalanceInfo.asset];
            if (rebalanceInfo.action == RebalanceAction.DEPOSIT) {
                require(
                    rebalanceInfo.amount <= yaConfig.liquidDeposit,
                    Errors.MFM_NOT_ENOUGH_FUNDS
                );
                adapter.deposit(rebalanceInfo.asset, rebalanceInfo.amount, rebalanceInfo.extra);
                yaConfig.liquidDeposit -= rebalanceInfo.amount;
                yaConfig.adapters[rebalanceInfo.adapterAddress].yieldDeposit += rebalanceInfo
                    .amount;
            } else if (rebalanceInfo.action == RebalanceAction.WITHDRAW) {
                require(
                    rebalanceInfo.amount <=
                        yaConfig.adapters[rebalanceInfo.adapterAddress].yieldDeposit,
                    Errors.MFM_NOT_ENOUGH_FUNDS
                );
                uint256 amount = adapter.withdraw(
                    rebalanceInfo.asset,
                    rebalanceInfo.amount,
                    rebalanceInfo.extra
                );
                require(amount == rebalanceInfo.amount, Errors.MFM_AMOUNT_MISMATCH);
                yaConfig.liquidDeposit += rebalanceInfo.amount;
                yaConfig.adapters[rebalanceInfo.adapterAddress].yieldDeposit -= rebalanceInfo
                    .amount;
            } else if (rebalanceInfo.action == RebalanceAction.REQUEST_WITHDRAW) {
                ILockedAdapter(address(adapter)).requestWithdraw(
                    rebalanceInfo.asset,
                    rebalanceInfo.amount,
                    rebalanceInfo.extra
                );
            }
            emit Rebalanced(
                msg.sender,
                rebalanceInfo.asset,
                rebalanceInfo.adapterAddress,
                rebalanceInfo.amount,
                rebalanceInfo.action
            );
        }
    }

    /**
     * @inheritdoc IMeldFarming
     */
    function deposit(address _asset, uint256 _amount, bytes calldata) external override onlyBridge {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];

        assetConfig.liquidDeposit += _amount;

        emit Deposited(_asset, _amount);
    }

    /**
     * @inheritdoc IMeldFarming
     */
    function withdraw(
        address _asset,
        uint256 _amount,
        bytes calldata _extra
    ) external override onlyBridge returns (uint256) {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        uint256 remainingAmount = _amount;

        if (remainingAmount > assetConfig.liquidDeposit) {
            remainingAmount -= assetConfig.liquidDeposit;
            assetConfig.liquidDeposit = 0;
            for (uint256 i = 0; i < assetConfig.numAdapters; i++) {
                address adapterAddress = assetConfig.adapterIndex[i];
                IMeldFarming adapter = IMeldFarming(adapterAddress);
                YieldAssetAdapter storage yaAdapter = assetConfig.adapters[adapterAddress];
                AdapterConfig memory adapterConfig = adapters[adapterAddress];
                if (!adapterConfig.enabled) {
                    continue;
                }
                uint256 adapterAvailableLiquidity = adapter.getAvailableLiquidity(_asset);
                if (adapterAvailableLiquidity == 0) {
                    continue;
                }
                if (adapterAvailableLiquidity >= remainingAmount) {
                    adapter.withdraw(_asset, remainingAmount, _extra);
                    yaAdapter.yieldDeposit -= remainingAmount;
                    remainingAmount = 0;
                    break;
                } else {
                    adapter.withdraw(_asset, adapterAvailableLiquidity, _extra);
                    yaAdapter.yieldDeposit = 0;
                    remainingAmount -= adapterAvailableLiquidity;
                }
            }
            require(remainingAmount == 0, Errors.MFM_NOT_ENOUGH_FUNDS);
        } else {
            assetConfig.liquidDeposit -= remainingAmount;
        }
        emit Withdrawn(_asset, _amount);

        return _amount;
    }

    /**
     * @inheritdoc IMeldFarming
     */
    function claimRewards(
        address _asset,
        bytes calldata _extra,
        bool _withdrawOnlyAvailable
    ) external override onlyRole(bridge.REBALANCER_ROLE()) returns (uint256) {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        require(assetConfig.numAdapters > 0, Errors.MFM_NO_ADAPTERS_CONFIGURED);
        uint256 totalRewards;
        for (uint256 i = 0; i < assetConfig.numAdapters; i++) {
            address adapterAddress = assetConfig.adapterIndex[i];
            YieldAssetAdapter storage yaAdapter = assetConfig.adapters[adapterAddress];
            AdapterConfig memory adapterConfig = adapters[adapterAddress];
            if (!adapterConfig.enabled) {
                continue;
            }
            uint256 rewards = IMeldFarming(adapterAddress).claimRewards(
                _asset,
                _extra,
                _withdrawOnlyAvailable
            );
            if (rewards > 0) {
                totalRewards += rewards;
                yaAdapter.lastTimestampRewardsClaimed = block.timestamp;
            }
            emit RewardsClaimed(msg.sender, _asset, adapterAddress, rewards);
        }
        IERC20(_asset).safeTransfer(treasury, totalRewards);
        return totalRewards;
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function getAllAdapters() external view override returns (AdapterConfig[] memory) {
        AdapterConfig[] memory adaptersConfig = new AdapterConfig[](numAdapters);
        for (uint256 i = 0; i < numAdapters; i++) {
            adaptersConfig[i] = adapters[adapterAddresses[i]];
        }
        return adaptersConfig;
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function getAdapter(
        address _adapterAddress
    ) external view override returns (AdapterConfig memory) {
        return adapters[_adapterAddress];
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function getYieldAssetConfig(
        address _asset
    )
        external
        view
        override
        returns (
            string[] memory assetAdapterIds,
            address[] memory assetAdapterAddresses,
            uint256[] memory yieldDeposit,
            uint256[] memory lastTimestampRewardsClaimed,
            uint256 liquidDeposit,
            uint256 totalDeposit,
            uint256 totalAvailableLiquidity
        )
    {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        uint256 assetNumAdapters = assetConfig.numAdapters;
        liquidDeposit = assetConfig.liquidDeposit;
        totalDeposit = liquidDeposit;
        totalAvailableLiquidity = liquidDeposit;
        assetAdapterIds = new string[](assetNumAdapters);
        yieldDeposit = new uint256[](assetNumAdapters);
        lastTimestampRewardsClaimed = new uint256[](assetNumAdapters);
        assetAdapterAddresses = new address[](assetNumAdapters);
        address tempAdapterAddress;
        YieldAssetAdapter memory tempAdapter;
        for (uint256 i = 0; i < assetNumAdapters; i++) {
            tempAdapterAddress = assetConfig.adapterIndex[i];
            assetAdapterIds[i] = adapters[tempAdapterAddress].adapterIdStr;
            tempAdapter = assetConfig.adapters[tempAdapterAddress];
            yieldDeposit[i] = tempAdapter.yieldDeposit;
            totalDeposit += tempAdapter.yieldDeposit;
            totalAvailableLiquidity += IMeldFarming(tempAdapterAddress).getAvailableLiquidity(
                _asset
            );
            assetAdapterAddresses[i] = tempAdapterAddress;
            lastTimestampRewardsClaimed[i] = tempAdapter.lastTimestampRewardsClaimed;
        }
    }

    /**
     * @inheritdoc IMeldFarmingManager
     */
    function getTotalDeposit(address _asset) external view override returns (uint256) {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        uint256 total = assetConfig.liquidDeposit;
        address tempAdapterAddress;
        for (uint256 i = 0; i < assetConfig.numAdapters; i++) {
            tempAdapterAddress = assetConfig.adapterIndex[i];
            total += assetConfig.adapters[tempAdapterAddress].yieldDeposit;
        }
        return total;
    }

    /**
     * @inheritdoc IMeldFarming
     * @dev This includes the funds in the Meld Farming Manager plus the funds in the non-locked adapters
     */
    function getAvailableLiquidity(address _asset) external view override returns (uint256) {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        uint256 total = assetConfig.liquidDeposit;
        address tempAdapterAddress;
        for (uint256 i = 0; i < assetConfig.numAdapters; i++) {
            tempAdapterAddress = assetConfig.adapterIndex[i];
            if (!adapters[tempAdapterAddress].locked) {
                total += IMeldFarming(tempAdapterAddress).getAvailableLiquidity(_asset);
            }
        }
        return total;
    }

    /**
     * @inheritdoc IMeldFarming
     * @dev This is the sum of the rewards of the adapters configured for the asset
     */
    function getRewardsAmount(address _asset) external view override returns (uint256) {
        YieldAssetConfig storage assetConfig = yieldAssetConfigs[_asset];
        uint256 total;
        address tempAdapterAddress;
        for (uint256 i = 0; i < assetConfig.numAdapters; i++) {
            tempAdapterAddress = assetConfig.adapterIndex[i];
            total += IMeldFarming(tempAdapterAddress).getRewardsAmount(_asset);
        }
        return total;
    }

    /**
     * @inheritdoc IMeldFarming
     * @dev This function is intended for the Yield Adapters, but this contract must implement the same interface
     */
    function meldFarmingManager() external view override returns (address) {
        return address(this);
    }

    /**
     * @inheritdoc IERC165
     */
    function supportsInterface(bytes4 _interfaceId) public pure override returns (bool) {
        return _interfaceId == type(IMeldFarming).interfaceId;
    }

    /**
     * @notice Private function to set the treasury address
     * @param _treasury Address of the treasury
     */
    function _setTreasury(address _treasury) private {
        require(_treasury != address(0), Errors.INVALID_ADDRESS);
        emit TreasuryUpdated(msg.sender, treasury, _treasury);
        treasury = _treasury;
    }

    /**
     * @notice Private function to safe approve all the tokens to the spender
     * @param _token Token to approve
     * @param _spender Spender to approve
     */
    function _safeApproveAll(IERC20 _token, address _spender) private {
        uint256 allowance = _token.allowance(address(this), _spender);
        uint256 increaseAllowance = type(uint256).max - allowance;
        if (increaseAllowance > 0) {
            _token.safeIncreaseAllowance(_spender, increaseAllowance);
        }
    }

    /**
     * @notice Private function to check if the adapter is enabled
     * @dev It reverts if the adapter is not enabled
     * @param _adapter Adapter configuration
     */
    function _checkAdapterEnabled(AdapterConfig memory _adapter) private pure {
        require(_adapter.enabled, Errors.MFM_ADAPTER_DISABLED);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "shanghai",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"address","name":"_wETH","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeERC1155Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"BridgeERC721Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executedBy","type":"address"},{"indexed":true,"internalType":"address","name":"meldFarmingManagerAddress","type":"address"}],"name":"MeldFarmingManagerDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executedBy","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"supported","type":"bool"}],"name":"SupportedTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executedBy","type":"address"},{"indexed":true,"internalType":"address","name":"wETH","type":"address"}],"name":"WETHAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"requestID","type":"bytes32"}],"name":"WithdrawnERC1155ToUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"requestID","type":"bytes32"}],"name":"WithdrawnERC721ToUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"requestID","type":"bytes32"}],"name":"WithdrawnToUser","type":"event"},{"inputs":[],"name":"CONFIGURATION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTION_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REBALANCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridgeERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"bridgeERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"checkRole","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFarmingManagerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestID","type":"bytes32"}],"name":"processedRequests","outputs":[{"internalType":"bool","name":"processed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_supported","type":"bool"}],"name":"setSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wETHAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_requestID","type":"bytes32"}],"name":"withdrawERC1155ToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address[]","name":"_tos","type":"address[]"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bytes32[]","name":"_requestIDs","type":"bytes32[]"}],"name":"withdrawERC1155ToUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32","name":"_requestID","type":"bytes32"}],"name":"withdrawERC721ToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address[]","name":"_tos","type":"address[]"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"bytes32[]","name":"_requestIDs","type":"bytes32[]"}],"name":"withdrawERC721ToUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_requestID","type":"bytes32"},{"internalType":"bytes","name":"_extra","type":"bytes"}],"name":"withdrawToUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address[]","name":"_tos","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"bytes32[]","name":"_requestIDs","type":"bytes32[]"},{"internalType":"bytes[]","name":"_extra","type":"bytes[]"}],"name":"withdrawToUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801562000010575f80fd5b5060405162006a8638038062006a8683398101604081905262000033916200027c565b6200003f5f846200011b565b600480546001600160a01b0319166001600160a01b03841690811790915560405133907ff54db3292d692c779cb5f30390edbd66b5ff7fab4b96b75549f4a7aafe02ff73905f90a33081604051620000979062000252565b6001600160a01b03928316815291166020820152604001604051809103905ff080158015620000c8573d5f803e3d5ffd5b50600580546001600160a01b0319166001600160a01b0392909216918217905560405133907f179637815c09dcd8c1f712be70e58e99066bd960f67b759a4f367516516e5d4e905f90a3505050620002c3565b62000127828262000145565b5f828152600160205260409020620001409082620001e4565b505050565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16620001e0575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200019f3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b5f620001fa836001600160a01b03841662000203565b90505b92915050565b5f8181526001830160205260408120546200024a57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155620001fd565b505f620001fd565b613bdf8062002ea783390190565b80516001600160a01b038116811462000277575f80fd5b919050565b5f805f606084860312156200028f575f80fd5b6200029a8462000260565b9250620002aa6020850162000260565b9150620002ba6040850162000260565b90509250925092565b612bd680620002d15f395ff3fe6080604052600436106101d3575f3560e01c8063799549ee116100fd578063c3de453d11610092578063dd84dc4c11610062578063dd84dc4c14610615578063e798646614610634578063f23a6e6114610653578063f89d699d1461067f575f80fd5b8063c3de453d1461058a578063ca15c873146105a9578063ce0fa5a9146105c8578063d547741f146105f6575f80fd5b8063a217fddf116100cd578063a217fddf1461050e578063abb50b1514610521578063b12ed45e14610529578063bc197c811461055c575f80fd5b8063799549ee146104925780639010d07c146104b157806390541601146104d057806391d14854146104ef575f80fd5b8063490b48f81161017357806368c4ac261161014357806368c4ac26146103ee578063708b0dbe1461041c57806374f8663b146104535780637846d1e414610473575f80fd5b8063490b48f81461035e5780634d388227146103915780635231f6ce146103b057806367f4a8f0146103cf575f80fd5b8063150b7a02116101ae578063150b7a02146102a0578063248a9ca3146102e45780632f2ff15d1461032057806336568abe1461033f575f80fd5b806301ffc9a71461022e5780630919a7891461026257806312d9a6ad14610281575f80fd5b3661022a57600454604080516080810190915260468082526001600160a01b03909216331491612ac06020830139906102285760405162461bcd60e51b815260040161021f919061214d565b60405180910390fd5b005b5f80fd5b348015610239575f80fd5b5061024d61024836600461217f565b61069c565b60405190151581526020015b60405180910390f35b34801561026d575f80fd5b5061022861027c3660046121c1565b6106c6565b34801561028c575f80fd5b5061022861029b36600461220a565b6108c6565b3480156102ab575f80fd5b506102cb6102ba366004612279565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610259565b3480156102ef575f80fd5b506103126102fe3660046122e3565b5f9081526020819052604090206001015490565b604051908152602001610259565b34801561032b575f80fd5b5061022861033a36600461220a565b6108d4565b34801561034a575f80fd5b5061022861035936600461220a565b6108fd565b348015610369575f80fd5b506103127fccc64574297998b6c3edf6078cc5e01268465ff116954e3af02ff3a70a730f4681565b34801561039c575f80fd5b506102286103ab3660046122fa565b610977565b3480156103bb575f80fd5b506102286103ca366004612322565b610a7f565b3480156103da575f80fd5b506102286103e93660046124d9565b610c2e565b3480156103f9575f80fd5b5061024d610408366004612595565b60026020525f908152604090205460ff1681565b348015610427575f80fd5b5060045461043b906001600160a01b031681565b6040516001600160a01b039091168152602001610259565b34801561045e575f80fd5b506103125f80516020612b8183398151915281565b34801561047e575f80fd5b5061022861048d3660046125ae565b610d2a565b34801561049d575f80fd5b506102286104ac366004612641565b610df9565b3480156104bc575f80fd5b5061043b6104cb366004612671565b610f50565b3480156104db575f80fd5b506102286104ea366004612691565b610f6e565b3480156104fa575f80fd5b5061024d61050936600461220a565b611065565b348015610519575f80fd5b506103125f81565b61022861108d565b348015610534575f80fd5b506103127f969e743677c83a4458df4afcef9c1049579c1137c04e48694290c3e5fe6ef47681565b348015610567575f80fd5b506102cb610576366004612747565b63bc197c8160e01b98975050505050505050565b348015610595575f80fd5b506102286105a43660046122fa565b611373565b3480156105b4575f80fd5b506103126105c33660046122e3565b6114ee565b3480156105d3575f80fd5b5061024d6105e23660046122e3565b60036020525f908152604090205460ff1681565b348015610601575f80fd5b5061022861061036600461220a565b611504565b348015610620575f80fd5b5061022861062f3660046127fa565b611528565b34801561063f575f80fd5b5061022861064e366004612868565b61188a565b34801561065e575f80fd5b506102cb61066d3660046127fa565b63f23a6e6160e01b9695505050505050565b34801561068a575f80fd5b506005546001600160a01b031661043b565b5f6001600160e01b03198216630271189760e51b14806106c057506106c08261190d565b92915050565b5f80516020612b818339815191526106dd81611931565b6001600160a01b0386165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915287919060ff1661073d5760405162461bcd60e51b815260040161021f919061214d565b505f83815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915284919060ff16156107a45760405162461bcd60e51b815260040161021f919061214d565b50845f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b815250906107ee5760405162461bcd60e51b815260040161021f919061214d565b50604051637921219560e11b81526001600160a01b038a169063f242432a906108219030908c908c908c9060040161289d565b5f604051808303815f87803b158015610838575f80fd5b505af115801561084a573d5f803e3d5ffd5b5050505f8681526003602052604090819020805460ff19166001179055518691506001600160a01b03808b1691908c16907fcd3cdba2c4a7a9fa5e8a62dd4a9567275257353804d0b4250b8416cbf6ca5201906108b3908c908c90918252602082015260400190565b60405180910390a4505050505050505050565b6108d0828261193e565b5050565b5f828152602081905260409020600101546108ee81611931565b6108f88383611997565b505050565b6001600160a01b038116331461096d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b606482015260840161021f565b6108d082826119b8565b6001600160a01b0382165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915283919060ff166109d75760405162461bcd60e51b815260040161021f919061214d565b50604051632142170760e11b8152336004820152306024820152604481018390526001600160a01b038416906342842e0e906064015f604051808303815f87803b158015610a23575f80fd5b505af1158015610a35573d5f803e3d5ffd5b50506040518481526001600160a01b03861692503391507f56000d41ed570386e6cbb91e291a2c55110aac38c413ee75bbfe7c9ce5104b0a906020015b60405180910390a3505050565b5f80516020612b81833981519152610a9681611931565b6001600160a01b0385165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915286919060ff16610af65760405162461bcd60e51b815260040161021f919061214d565b505f83815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915284919060ff1615610b5d5760405162461bcd60e51b815260040161021f919061214d565b50604051632142170760e11b81523060048201526001600160a01b038781166024830152604482018790528816906342842e0e906064015f604051808303815f87803b158015610bab575f80fd5b505af1158015610bbd573d5f803e3d5ffd5b5050505f8581526003602052604090819020805460ff19166001179055518591506001600160a01b0380891691908a16907fce160f8f7991700e359926e01fdd784c1991356d33ae3809a305e4eec088bc5d90610c1d908a815260200190565b60405180910390a450505050505050565b83518551148015610c40575082518451145b8015610c4c5750825181145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610c975760405162461bcd60e51b815260040161021f919061214d565b505f5b8551811015610d2157610d1987878381518110610cb957610cb96128d4565b6020026020010151878481518110610cd357610cd36128d4565b6020026020010151878581518110610ced57610ced6128d4565b6020026020010151878787818110610d0757610d076128d4565b905060200281019061062f91906128e8565b600101610c9a565b50505050505050565b81518351148015610d3c575080518251145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610d875760405162461bcd60e51b815260040161021f919061214d565b505f5b8351811015610df257610dea85858381518110610da957610da96128d4565b6020026020010151858481518110610dc357610dc36128d4565b6020026020010151858581518110610ddd57610ddd6128d4565b6020026020010151610a7f565b600101610d8a565b5050505050565b6001600160a01b0383165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915284919060ff16610e595760405162461bcd60e51b815260040161021f919061214d565b50815f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b81525090610ea35760405162461bcd60e51b815260040161021f919061214d565b50604051637921219560e11b81526001600160a01b0386169063f242432a90610ed690339030908990899060040161289d565b5f604051808303815f87803b158015610eed575f80fd5b505af1158015610eff573d5f803e3d5ffd5b505060408051878152602081018790526001600160a01b03891693503392507f83ab655dce8564238f4015e1e43bccfe0fc818637dbe61a3c6223770a773c821910160405180910390a35050505050565b5f828152600160205260408120610f6790836119d9565b9392505050565b82518451148015610f80575080518351145b8015610f8d575081518351145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610fd85760405162461bcd60e51b815260040161021f919061214d565b505f5b845181101561105d5761105586868381518110610ffa57610ffa6128d4565b6020026020010151868481518110611014576110146128d4565b602002602001015186858151811061102e5761102e6128d4565b6020026020010151868681518110611048576110486128d4565b60200260200101516106c6565b600101610fdb565b505050505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8052600260209081527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b546040805160608101909152603180825260ff90921692909190612b3090830139906110f75760405162461bcd60e51b815260040161021f919061214d565b5060408051808201909152600e81526d125b9d985b1a5908185b5bdd5b9d60921b60208201523461113b5760405162461bcd60e51b815260040161021f919061214d565b50600480546040516370a0823160e01b815230928101929092526001600160a01b0316905f9082906370a0823190602401602060405180830381865afa158015611187573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ab919061292b565b9050816001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b1580156111e6575f80fd5b505af11580156111f8573d5f803e3d5ffd5b505050505080346112099190612956565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561124b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061126f919061292b565b146040518060600160405280602a8152602001612b06602a9139906112a75760405162461bcd60e51b815260040161021f919061214d565b506005546004546112c5916001600160a01b039182169116346119e4565b60055460048054604051630937b85760e31b81526001600160a01b0391821692810192909252346024830152606060448301525f6064830152909116906349bdc2b8906084015f604051808303815f87803b158015611322575f80fd5b505af1158015611334573d5f803e3d5ffd5b50506040513481525f92503391507f8e45dd3e0559b56feca4f095454c145dbe2acb06c789c0486fe2b0f1e609a0019060200160405180910390a35050565b6001600160a01b0382165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915283919060ff166113d35760405162461bcd60e51b815260040161021f919061214d565b50815f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b8152509061141d5760405162461bcd60e51b815260040161021f919061214d565b5060055461143a906001600160a01b038681169133911686611a47565b600554604051630937b85760e31b81526001600160a01b03868116600483015260248201869052606060448301525f6064830152909116906349bdc2b8906084015f604051808303815f87803b158015611492575f80fd5b505af11580156114a4573d5f803e3d5ffd5b50506040518581526001600160a01b03871692503391507f8e45dd3e0559b56feca4f095454c145dbe2acb06c789c0486fe2b0f1e609a0019060200160405180910390a350505050565b5f8181526001602052604081206106c090611a85565b5f8281526020819052604090206001015461151e81611931565b6108f883836119b8565b5f80516020612b8183398151915261153f81611931565b6001600160a01b0387165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915288919060ff1661159f5760405162461bcd60e51b815260040161021f919061214d565b505f85815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915286919060ff16156116065760405162461bcd60e51b815260040161021f919061214d565b50865f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b815250906116505760405162461bcd60e51b815260040161021f919061214d565b506001600160a01b038a1661178857600554600480546040516331f0926560e01b81526001600160a01b03938416936331f092659361169993909116918d918c918c9101612991565b6020604051808303815f875af11580156116b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116d9919061292b565b506005546004546116f8916001600160a01b039182169116308b611a47565b60048054604051632e1a7d4d60e01b81529182018a90526001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611739575f80fd5b505af115801561174b573d5f803e3d5ffd5b50506040516001600160a01b038c1692508a156108fc0291508a905f818181858888f19350505050158015611782573d5f803e3d5ffd5b5061181a565b6005546040516331f0926560e01b81526001600160a01b03909116906331f09265906117be908d908c908b908b90600401612991565b6020604051808303815f875af11580156117da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117fe919061292b565b5060055461181a906001600160a01b038c811691168b8b611a47565b5f8781526003602052604090819020805460ff191660011790555187906001600160a01b03808c1691908d16907f0d926ad85030030cad809df6a05eb364038b87665b35bee01a3656889901116f90611876908d815260200190565b60405180910390a450505050505050505050565b7f969e743677c83a4458df4afcef9c1049579c1137c04e48694290c3e5fe6ef4766118b481611931565b6001600160a01b0383165f81815260026020908152604091829020805460ff1916861515908117909155915191825233917f9db3eb580aece44728f5d3f04a2a246f883906d2391124024cfd10c5d338b5ba9101610a72565b5f6001600160e01b03198216635a05180f60e01b14806106c057506106c082611a8e565b61193b813361193e565b50565b6119488282611065565b6108d05761195581611ac2565b611960836020611ad4565b6040516020016119719291906129c2565b60408051601f198184030181529082905262461bcd60e51b825261021f9160040161214d565b6119a18282611c6a565b5f8281526001602052604090206108f89082611ced565b6119c28282611d01565b5f8281526001602052604090206108f89082611d65565b5f610f678383611d79565b6040516001600160a01b0383166024820152604481018290526108f890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611d9f565b6040516001600160a01b0380851660248301528316604482015260648101829052611a7f9085906323b872dd60e01b90608401611a10565b50505050565b5f6106c0825490565b5f6001600160e01b03198216637965db0b60e01b14806106c057506301ffc9a760e01b6001600160e01b03198316146106c0565b60606106c06001600160a01b03831660145b60605f611ae2836002612a36565b611aed906002612956565b67ffffffffffffffff811115611b0557611b05612361565b6040519080825280601f01601f191660200182016040528015611b2f576020820181803683370190505b509050600360fc1b815f81518110611b4957611b496128d4565b60200101906001600160f81b03191690815f1a905350600f60fb1b81600181518110611b7757611b776128d4565b60200101906001600160f81b03191690815f1a9053505f611b99846002612a36565b611ba4906001612956565b90505b6001811115611c1b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611bd857611bd86128d4565b1a60f81b828281518110611bee57611bee6128d4565b60200101906001600160f81b03191690815f1a90535060049490941c93611c1481612a4d565b9050611ba7565b508315610f675760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161021f565b611c748282611065565b6108d0575f828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611ca93390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f610f67836001600160a01b038416611e72565b611d0b8282611065565b156108d0575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f610f67836001600160a01b038416611ebe565b5f825f018281548110611d8e57611d8e6128d4565b905f5260205f200154905092915050565b5f611df3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611fa19092919063ffffffff16565b905080515f1480611e13575080806020019051810190611e139190612a62565b6108f85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161021f565b5f818152600183016020526040812054611eb757508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556106c0565b505f6106c0565b5f8181526001830160205260408120548015611f98575f611ee0600183612a7d565b85549091505f90611ef390600190612a7d565b9050818114611f52575f865f018281548110611f1157611f116128d4565b905f5260205f200154905080875f018481548110611f3157611f316128d4565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611f6357611f63612a90565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506106c0565b5f9150506106c0565b6060611faf84845f85611fb7565b949350505050565b6060824710156120185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161021f565b5f80866001600160a01b031685876040516120339190612aa4565b5f6040518083038185875af1925050503d805f811461206d576040519150601f19603f3d011682016040523d82523d5f602084013e612072565b606091505b50915091506120838783838761208e565b979650505050505050565b606083156120fc5782515f036120f5576001600160a01b0385163b6120f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161021f565b5081611faf565b611faf83838151156121115781518083602001fd5b8060405162461bcd60e51b815260040161021f919061214d565b5f5b8381101561214557818101518382015260200161212d565b50505f910152565b602081525f825180602084015261216b81604085016020870161212b565b601f01601f19169190910160400192915050565b5f6020828403121561218f575f80fd5b81356001600160e01b031981168114610f67575f80fd5b80356001600160a01b03811681146121bc575f80fd5b919050565b5f805f805f60a086880312156121d5575f80fd5b6121de866121a6565b94506121ec602087016121a6565b94979496505050506040830135926060810135926080909101359150565b5f806040838503121561221b575f80fd5b8235915061222b602084016121a6565b90509250929050565b5f8083601f840112612244575f80fd5b50813567ffffffffffffffff81111561225b575f80fd5b602083019150836020828501011115612272575f80fd5b9250929050565b5f805f805f6080868803121561228d575f80fd5b612296866121a6565b94506122a4602087016121a6565b935060408601359250606086013567ffffffffffffffff8111156122c6575f80fd5b6122d288828901612234565b969995985093965092949392505050565b5f602082840312156122f3575f80fd5b5035919050565b5f806040838503121561230b575f80fd5b612314836121a6565b946020939093013593505050565b5f805f8060808587031215612335575f80fd5b61233e856121a6565b935061234c602086016121a6565b93969395505050506040820135916060013590565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561239e5761239e612361565b604052919050565b5f67ffffffffffffffff8211156123bf576123bf612361565b5060051b60200190565b5f82601f8301126123d8575f80fd5b813560206123ed6123e8836123a6565b612375565b8083825260208201915060208460051b87010193508684111561240e575f80fd5b602086015b8481101561243157612424816121a6565b8352918301918301612413565b509695505050505050565b5f82601f83011261244b575f80fd5b8135602061245b6123e8836123a6565b8083825260208201915060208460051b87010193508684111561247c575f80fd5b602086015b848110156124315780358352918301918301612481565b5f8083601f8401126124a8575f80fd5b50813567ffffffffffffffff8111156124bf575f80fd5b6020830191508360208260051b8501011115612272575f80fd5b5f805f805f8060a087890312156124ee575f80fd5b6124f7876121a6565b9550602087013567ffffffffffffffff80821115612513575f80fd5b61251f8a838b016123c9565b96506040890135915080821115612534575f80fd5b6125408a838b0161243c565b95506060890135915080821115612555575f80fd5b6125618a838b0161243c565b94506080890135915080821115612576575f80fd5b5061258389828a01612498565b979a9699509497509295939492505050565b5f602082840312156125a5575f80fd5b610f67826121a6565b5f805f80608085870312156125c1575f80fd5b6125ca856121a6565b9350602085013567ffffffffffffffff808211156125e6575f80fd5b6125f2888389016123c9565b94506040870135915080821115612607575f80fd5b6126138883890161243c565b93506060870135915080821115612628575f80fd5b506126358782880161243c565b91505092959194509250565b5f805f60608486031215612653575f80fd5b61265c846121a6565b95602085013595506040909401359392505050565b5f8060408385031215612682575f80fd5b50508035926020909101359150565b5f805f805f60a086880312156126a5575f80fd5b6126ae866121a6565b9450602086013567ffffffffffffffff808211156126ca575f80fd5b6126d689838a016123c9565b955060408801359150808211156126eb575f80fd5b6126f789838a0161243c565b9450606088013591508082111561270c575f80fd5b61271889838a0161243c565b9350608088013591508082111561272d575f80fd5b5061273a8882890161243c565b9150509295509295909350565b5f805f805f805f8060a0898b03121561275e575f80fd5b612767896121a6565b975061277560208a016121a6565b9650604089013567ffffffffffffffff80821115612791575f80fd5b61279d8c838d01612498565b909850965060608b01359150808211156127b5575f80fd5b6127c18c838d01612498565b909650945060808b01359150808211156127d9575f80fd5b506127e68b828c01612234565b999c989b5096995094979396929594505050565b5f805f805f8060a0878903121561280f575f80fd5b612818876121a6565b9550612826602088016121a6565b94506040870135935060608701359250608087013567ffffffffffffffff81111561284f575f80fd5b61258389828a01612234565b801515811461193b575f80fd5b5f8060408385031215612879575f80fd5b612882836121a6565b915060208301356128928161285b565b809150509250929050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a0608082018190525f9082015260c00190565b634e487b7160e01b5f52603260045260245ffd5b5f808335601e198436030181126128fd575f80fd5b83018035915067ffffffffffffffff821115612917575f80fd5b602001915036819003821315612272575f80fd5b5f6020828403121561293b575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106c0576106c0612942565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201525f6129b8606083018486612969565b9695505050505050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f83516129f981601785016020880161212b565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612a2a81602884016020880161212b565b01602801949350505050565b80820281158282048414176106c0576106c0612942565b5f81612a5b57612a5b612942565b505f190190565b5f60208284031215612a72575f80fd5b8151610f678161285b565b818103818111156106c0576106c0612942565b634e487b7160e01b5f52603160045260245ffd5b5f8251612ab581846020870161212b565b919091019291505056fe4d656c6442726964676552656365697665723a204f6e6c7920574554482063616e206465706f73697420455448206469726563746c7920746f2074686520636f6e74726163744d656c6442726964676552656365697665723a204e6174697665207772617070696e67206661696c65644d656c6442726964676552656365697665723a204e617469766520546f6b656e206973206e6f7420737570706f72746564546f6b656e206973206e6f7420737570706f7274656400000000000000000000f21a16feb1ed068bfca4f16029f44a27181a38cc067de137a57f47ae74f52a11a26469706673582212205602ce934a24f938602e4872ba1e0da651031a7214f26d78f97271b2f60eee7264736f6c63430008180033608060405234801562000010575f80fd5b5060405162003bdf38038062003bdf83398101604081905262000033916200016c565b600480546001600160a01b0319166001600160a01b03841690811790915560405190815233907fc0634c245ce7b7b309744c30c030a783629555dc9f0c2c4cb54bdc9d9812d6209060200160405180910390a2620000918162000099565b5050620001f0565b60408051808201909152600f81526e496e76616c6964206164647265737360881b60208201526001600160a01b038216620000f25760405162461bcd60e51b8152600401620000e99190620001a2565b60405180910390fd5b506005546040516001600160a01b0380841692169033907f23c12d5579081c5f1077c04a6b1c114d0f3de239e81a436836d30ecb099ffa13905f90a4600580546001600160a01b0319166001600160a01b0392909216919091179055565b80516001600160a01b038116811462000167575f80fd5b919050565b5f80604083850312156200017e575f80fd5b620001898362000150565b9150620001996020840162000150565b90509250929050565b5f602080835283518060208501525f5b81811015620001d057858101830151858201604001528201620001b2565b505f604082860101526040601f19601f8301168501019250505092915050565b6139e180620001fe5f395ff3fe608060405234801561000f575f80fd5b5060043610610127575f3560e01c8063b732a36e116100a9578063dbe934511161006e578063dbe93451146102a1578063dff07da2146102b4578063e31ada97146102da578063e78cea92146102ef578063f0f4426014610302575f80fd5b8063b732a36e14610242578063b74d3b1514610255578063c157c57c14610268578063c876d28114610288578063c9637cc31461029b575f80fd5b8063776941a2116100ef578063776941a2146101d85780637c917038146101eb578063857184d1146102135780638ba1b28414610226578063a87461b514610239575f80fd5b806301ffc9a71461012b578063266e2bd81461016457806331f092651461018557806349bdc2b81461019857806361d027b3146101ad575b5f80fd5b61014f610139366004612e69565b6001600160e01b03191663fb9b90f960e01b1490565b60405190151581526020015b60405180910390f35b610177610172366004612ebe565b610315565b60405190815260200161015b565b610177610193366004612f1d565b6103fc565b6101ab6101a6366004612f1d565b610802565b005b6005546101c0906001600160a01b031681565b6040516001600160a01b03909116815260200161015b565b6101ab6101e6366004612fb8565b6108bf565b6101c06101f9366004613079565b5f602081905290815260409020546001600160a01b031681565b610177610221366004612ebe565b611188565b6101ab6102343660046130a8565b6111f1565b61017760025481565b6101776102503660046130df565b611371565b6101ab610263366004613142565b6116e2565b61027b610276366004612ebe565b611b26565b60405161015b9190613281565b6101ab610296366004613293565b611c30565b306101c0565b6101776102af366004612ebe565b612329565b6102c76102c2366004612ebe565b6123e1565b60405161015b9796959493929190613373565b6102e2612793565b60405161015b9190613427565b6004546101c0906001600160a01b031681565b6101ab610310366004612ebe565b612928565b6001600160a01b0381165f908152600360205260408120805482805b83600301548110156103f2575f818152600185810160209081526040808420546001600160a01b0316808552918390529092200154909250610100900460ff166103ea576040516304cdc57b60e31b81526001600160a01b03878116600483015283169063266e2bd890602401602060405180830381865afa1580156103b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103dd9190613489565b6103e790846134b4565b92505b600101610331565b5090949350505050565b600454604080516060810190915260368082525f926001600160a01b0316331491906138eb60208301399061044d5760405162461bcd60e51b815260040161044491906134cd565b60405180910390fd5b506001600160a01b0385165f9081526003602052604090208054859081111561079957815461047c90826134df565b5f8084559091505b8260030154811015610758575f818152600180850160209081526040808420546001600160a01b0316808552600288018352818520939092528084208151608081019092528054929485949390929190829082906104e1906134f2565b80601f016020809104026020016040519081016040528092919081815260200182805461050d906134f2565b80156105585780601f1061052f57610100808354040283529160200191610558565b820191905f5260205f20905b81548152906001019060200180831161053b57829003601f168201915b50505091835250506001919091015460ff80821615156020808501919091526101008304821615156040850152620100009092041615156060909201919091528101519091506105ab5750505050610750565b6040516304cdc57b60e31b81526001600160a01b038d811660048301525f919085169063266e2bd890602401602060405180830381865afa1580156105f2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106169190613489565b9050805f03610629575050505050610750565b8681106106c857836001600160a01b03166331f092658e898e8e6040518563ffffffff1660e01b8152600401610662949392919061354c565b6020604051808303815f875af115801561067e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106a29190613489565b5086835f015f8282546106b591906134df565b909155505f975061075895505050505050565b836001600160a01b03166331f092658e838e8e6040518563ffffffff1660e01b81526004016106fa949392919061354c565b6020604051808303815f875af1158015610716573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073a9190613489565b505f835561074881886134df565b965050505050505b600101610484565b50805f1460405180606001604052806024815260200161386260249139906107935760405162461bcd60e51b815260040161044491906134cd565b506107b1565b80825f015f8282546107ab91906134df565b90915550505b866001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5876040516107ec91815260200190565b60405180910390a285925050505b949350505050565b600454604080516060810190915260368082526001600160a01b039092163314916138eb6020830139906108495760405162461bcd60e51b815260040161044491906134cd565b506001600160a01b0384165f9081526003602052604081208054909185918391906108759084906134b4565b90915550506040518481526001600160a01b038616907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c49060200160405180910390a25050505050565b60048054604080516358976a2f60e11b815290516001600160a01b039092169263b12ed45e9282820192602092908290030181865afa158015610904573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109289190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b15801561096e575f80fd5b505afa158015610980573d5f803e3d5ffd5b5050506001600160a01b0384165f90815260036020819052604082208551918101549093506109af91906134b4565b6001600160401b038111156109c6576109c6612f74565b6040519080825280602002602001820160405280156109ef578160200160208202803683370190505b5090505f610a1c60405180608001604052805f81526020015f81526020015f81526020015f151581525090565b6003840154600454610a389089906001600160a01b03166129fa565b5f5b8751811015610c425760015f898381518110610a5857610a5861357d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2060010160029054906101000a900460ff166040518060600160405280602a8152602001613838602a913990610ac75760405162461bcd60e51b815260040161044491906134cd565b50878181518110610ada57610ada61357d565b6020908102919091018101516001600160a01b0381165f9081526002808a01845260409182902082516080810184528154815260018201549581019590955290810154918401919091526003015460ff161580156060840152909550909350610b79578385846020015181518110610b5457610b5461357d565b60200260200101906001600160a01b031690816001600160a01b031681525050610c3a565b83858381518110610b8c57610b8c61357d565b6001600160a01b039283166020918202929092018101919091525f84815260018981018352604080832080546001600160a01b031916958a1695861790558051608081018252838152808501888152818301858152606083018581529786526002808f019097529290942090518155925191830191909155519181019190915590516003909101805460ff1916911515919091179055610c2c89856129fa565b81610c3681613591565b9250505b600101610a3a565b50876001600160a01b0316336001600160a01b03167f78a6368a6b0bcb8891b5e0283fa8cb2add1faf3bd518bba5d2954cf46d3c1c1989604051610c8691906135a9565b60405180910390a3805f03610c9f575050505050505050565b5f80805b8760030154811015611153575f6001600160a01b0316878281518110610ccb57610ccb61357d565b60200260200101516001600160a01b03160361114b575f81815260208181526040808320546001600160a01b03168084526001909252808320815160808101909252805492939282908290610d1f906134f2565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4b906134f2565b8015610d965780601f10610d6d57610100808354040283529160200191610d96565b820191905f5260205f20905b815481529060010190602001808311610d7957829003601f168201915b50505091835250506001919091015460ff808216151560208401526101008204811615156040840152620100009091041615156060909101529050610dda81612a95565b5f8a6002015f846001600160a01b03166001600160a01b031681526020019081526020015f205f01549050826001600160a01b03166331f092658f836040518363ffffffff1660e01b8152600401610e559291906001600160a01b0392909216825260208201526060604082018190525f9082015260800190565b6020604051808303815f875af1158015610e71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e959190613489565b8b5f015f828254610ea691906134b4565b9091555050604051635b9951b760e11b81526001600160a01b038f81166004830152606060248301525f60648301819052604483015284169063b732a36e906084016020604051808303815f875af1158015610f04573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f289190613489565b9450610f3485876134b4565b9550826001600160a01b03168e6001600160a01b0316336001600160a01b03167f5637d7f962248a7f05a7ab69eec6446e31f3d0a299d997f135a65c62806e789188604051610f8591815260200190565b60405180910390a46001600160a01b0383165f9081526002808d01602052604082208281556001810183905590810191909155600301805460ff191690555b83871115611147575f8a610fd960018a6134df565b81518110610fe957610fe961357d565b60200260200101516001600160a01b03160315611135578961100c6001896134df565b8151811061101c5761101c61357d565b60200260200101518a85815181106110365761103661357d565b60200260200101906001600160a01b031690816001600160a01b031681525050838b6002015f8c878151811061106e5761106e61357d565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f20600101819055508984815181106110ae576110ae61357d565b60200260200101518b6001015f8681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f8a6001896110fb91906134df565b8151811061110b5761110b61357d565b6001600160a01b03909216602092830291909101909101528661112d816135bb565b975050611147565b8661113f816135bb565b975050610fc4565b5050505b600101610ca3565b5088516003880155811561117b5760055461117b906001600160a01b038c8116911684612ad1565b505050505050505b505050565b6001600160a01b0381165f908152600360205260408120805482805b83600301548110156103f2575f8181526001850160209081526040808320546001600160a01b031680845260028801909252909120549092506111e790846134b4565b92506001016111a4565b60048054604080516358976a2f60e11b815290516001600160a01b039092169263b12ed45e9282820192602092908290030181865afa158015611236573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061125a9190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b1580156112a0575f80fd5b505afa1580156112b2573d5f803e3d5ffd5b5050506001600160a01b0384165f9081526001602081815260409283902091820154835160608101909452602a80855292945060ff620100009091041692919061383890830139906113175760405162461bcd60e51b815260040161044491906134cd565b5060018101805460ff19168415159081179091556040519081526001600160a01b0385169033907f62b76bfed3e25f37ab2de632c70377774c2945b0ff78df201c44268cc04a73ce9060200160405180910390a350505050565b5f60045f9054906101000a90046001600160a01b03166001600160a01b031663490b48f86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113e69190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b15801561142c575f80fd5b505afa15801561143e573d5f803e3d5ffd5b505050505f60035f886001600160a01b03166001600160a01b031681526020019081526020015f2090505f8160030154116040518060600160405280602a81526020016138c1602a9139906114a65760405162461bcd60e51b815260040161044491906134cd565b505f805b82600301548110156116bc575f818152600180850160209081526040808420546001600160a01b031680855260028801835281852093909252808420815160808101909252805492949282908290611501906134f2565b80601f016020809104026020016040519081016040528092919081815260200182805461152d906134f2565b80156115785780601f1061154f57610100808354040283529160200191611578565b820191905f5260205f20905b81548152906001019060200180831161155b57829003601f168201915b50505091835250506001919091015460ff80821615156020808501919091526101008304821615156040850152620100009092041615156060909201919091528101519091506115ca575050506116b4565b5f836001600160a01b031663b732a36e8e8e8e8e6040518563ffffffff1660e01b81526004016115fd94939291906135d0565b6020604051808303815f875af1158015611619573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061163d9190613489565b905080156116585761164f81876134b4565b42600285015595505b836001600160a01b03168d6001600160a01b0316336001600160a01b03167f5637d7f962248a7f05a7ab69eec6446e31f3d0a299d997f135a65c62806e7891846040516116a791815260200190565b60405180910390a4505050505b6001016114aa565b506005546116d7906001600160a01b038a8116911683612ad1565b979650505050505050565b60048054604080516358976a2f60e11b815290516001600160a01b039092169263b12ed45e9282820192602092908290030181865afa158015611727573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174b9190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b158015611791575f80fd5b505afa1580156117a3573d5f803e3d5ffd5b505050505f84511160405180606001604052806026815260200161394860269139906117e25760405162461bcd60e51b815260040161044491906134cd565b5060015f846001600160a01b03166001600160a01b031681526020019081526020015f2060010160029054906101000a900460ff16156040518060600160405280602a81526020016137eb602a91399061184f5760405162461bcd60e51b815260040161044491906134cd565b5060408051808201909152600f81526e496e76616c6964206164647265737360881b60208201526001600160a01b03841661189d5760405162461bcd60e51b815260040161044491906134cd565b506040516301ffc9a760e01b815263fb9b90f960e01b600482015283906001600160a01b038216906301ffc9a790602401602060405180830381865afa1580156118e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190d9190613607565b6040518060600160405280603b8152602001613886603b9139906119445760405162461bcd60e51b815260040161044491906134cd565b50306001600160a01b0316816001600160a01b031663c9637cc36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561198b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119af9190613622565b6001600160a01b0316146040518060600160405280603e815260200161396e603e9139906119f05760405162461bcd60e51b815260040161044491906134cd565b50604080516080810182528681526001602080830182905286151583850152606083018290526001600160a01b0388165f9081529190529190912081518190611a399082613688565b50602082810151600190920180546040808601516060909601511515620100000262ff0000199615156101000261ff00199615159690961661ffff1990931692909217949094179490941693909317909255600280545f9081529283905290822080546001600160a01b0388166001600160a01b0319909116179055805491611ac183613591565b9190505550836001600160a01b031685604051611ade9190613747565b604080519182900382203383528615156020840152917ffeb85e1b59a8e75692b36f1d1165bbd12f7b43da4c5b8281e2fba4ba1315a963910160405180910390a35050505050565b6040805160808101825260608082525f602083018190529282018390528101919091526001600160a01b0382165f9081526001602052604090819020815160808101909252805482908290611b7a906134f2565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba6906134f2565b8015611bf15780601f10611bc857610100808354040283529160200191611bf1565b820191905f5260205f20905b815481529060010190602001808311611bd457829003601f168201915b50505091835250506001919091015460ff8082161515602084015261010082048116151560408401526201000090910416151560609091015292915050565b6004805460408051630921691f60e31b815290516001600160a01b039092169263490b48f89282820192602092908290030181865afa158015611c75573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c999190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b158015611cdf575f80fd5b505afa158015611cf1573d5f803e3d5ffd5b5050604080518082019091526014815273092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b602082015291505082611d3f5760405162461bcd60e51b815260040161044491906134cd565b505f5b828110156123235736848483818110611d5d57611d5d61357d565b9050602002810190611d6f9190613762565b9050611e7560015f611d876040850160208601612ebe565b6001600160a01b03166001600160a01b031681526020019081526020015f206040518060800160405290815f82018054611dc0906134f2565b80601f0160208091040260200160405190810160405280929190818152602001828054611dec906134f2565b8015611e375780601f10611e0e57610100808354040283529160200191611e37565b820191905f5260205f20905b815481529060010190602001808311611e1a57829003601f168201915b50505091835250506001919091015460ff80821615156020840152610100820481161515604084015262010000909104161515606090910152612a95565b5f611e866040830160208401612ebe565b90505f600381611e996020860186612ebe565b6001600160a01b0316815260208101919091526040015f2090506001611ec5608085016060860161378a565b6003811115611ed657611ed6613776565b0361200857805f0154836040013511156040518060600160405280602481526020016138626024913990611f1d5760405162461bcd60e51b815260040161044491906134cd565b506001600160a01b0382166349bdc2b8611f3a6020860186612ebe565b6040860135611f4c60808801886137a8565b6040518563ffffffff1660e01b8152600401611f6b949392919061354c565b5f604051808303815f87803b158015611f82575f80fd5b505af1158015611f94573d5f803e3d5ffd5b505050508260400135815f015f828254611fae91906134df565b90915550506040830180359060028301905f90611fce9060208801612ebe565b6001600160a01b03166001600160a01b031681526020019081526020015f205f015f828254611ffd91906134b4565b909155506122899050565b600261201a608085016060860161378a565b600381111561202b5761202b613776565b036121e657600281015f6120456040860160208701612ebe565b6001600160a01b03166001600160a01b031681526020019081526020015f205f01548360400135111560405180606001604052806024815260200161386260249139906120a55760405162461bcd60e51b815260040161044491906134cd565b505f6001600160a01b0383166331f092656120c36020870187612ebe565b60408701356120d560808901896137a8565b6040518563ffffffff1660e01b81526004016120f4949392919061354c565b6020604051808303815f875af1158015612110573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121349190613489565b90508360400135811460405180606001604052806023815260200161381560239139906121745760405162461bcd60e51b815260040161044491906134cd565b508360400135825f015f82825461218b91906134b4565b90915550506040840180359060028401905f906121ab9060208901612ebe565b6001600160a01b03166001600160a01b031681526020019081526020015f205f015f8282546121da91906134df565b90915550612289915050565b60036121f8608085016060860161378a565b600381111561220957612209613776565b03612289576001600160a01b038216630f51fc2661222a6020860186612ebe565b604086013561223c60808801886137a8565b6040518563ffffffff1660e01b815260040161225b949392919061354c565b5f604051808303815f87803b158015612272575f80fd5b505af1158015612284573d5f803e3d5ffd5b505050505b612299608084016060850161378a565b60038111156122aa576122aa613776565b6122ba6040850160208601612ebe565b6001600160a01b03166122d06020860186612ebe565b604080513381528188013560208201526001600160a01b0392909216917fa742c9be7d2f68dbf5362a00c7acaf4297dc2764f3d57430595235925d76afe6910160405180910390a4505050600101611d42565b50505050565b6001600160a01b0381165f9081526003602052604081208180805b83600301548110156103f2575f8181526001850160205260409081902054905163dbe9345160e01b81526001600160a01b0388811660048301529091169250829063dbe9345190602401602060405180830381865afa1580156123a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123cd9190613489565b6123d790846134b4565b9250600101612344565b6001600160a01b0381165f908152600360208190526040909120908101548154606092839283928392909182918291806001600160401b0381111561242857612428612f74565b60405190808252806020026020018201604052801561245b57816020015b60608152602001906001900390816124465790505b509850806001600160401b0381111561247657612476612f74565b60405190808252806020026020018201604052801561249f578160200160208202803683370190505b509650806001600160401b038111156124ba576124ba612f74565b6040519080825280602002602001820160405280156124e3578160200160208202803683370190505b509550806001600160401b038111156124fe576124fe612f74565b604051908082528060200260200182016040528015612527578160200160208202803683370190505b5097505f61255460405180608001604052805f81526020015f81526020015f81526020015f151581525090565b5f5b83811015612783575f818152600180870160209081526040808420546001600160a01b031680855292909152909120805491945090612594906134f2565b80601f01602080910402602001604051908101604052809291908181526020018280546125c0906134f2565b801561260b5780601f106125e25761010080835404028352916020019161260b565b820191905f5260205f20905b8154815290600101906020018083116125ee57829003601f168201915b50505050508c82815181106126225761262261357d565b6020908102919091018101919091526001600160a01b0384165f9081526002808801835260409182902082516080810184528154808252600183015495820195909552918101549282019290925260039091015460ff16151560608201528b519093508b90839081106126975761269761357d565b602090810291909101015281516126ae90886134b4565b6040516304cdc57b60e31b81526001600160a01b038f811660048301529198509084169063266e2bd890602401602060405180830381865afa1580156126f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061271a9190613489565b61272490876134b4565b9550828b82815181106127395761273961357d565b60200260200101906001600160a01b031690816001600160a01b03168152505081604001518982815181106127705761277061357d565b6020908102919091010152600101612556565b5050505050919395979092949650565b60605f6002546001600160401b038111156127b0576127b0612f74565b60405190808252806020026020018201604052801561280157816020015b6040805160808101825260608082525f60208084018290529383018190529082015282525f199092019101816127ce5790505b5090505f5b600254811015612922575f81815260208181526040808320546001600160a01b0316835260019091529081902081516080810190925280548290829061284b906134f2565b80601f0160208091040260200160405190810160405280929190818152602001828054612877906134f2565b80156128c25780601f10612899576101008083540402835291602001916128c2565b820191905f5260205f20905b8154815290600101906020018083116128a557829003601f168201915b50505091835250506001919091015460ff80821615156020840152610100820481161515604084015262010000909104161515606090910152825183908390811061290f5761290f61357d565b6020908102919091010152600101612806565b50919050565b60048054604080516358976a2f60e11b815290516001600160a01b039092169263b12ed45e9282820192602092908290030181865afa15801561296d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129919190613489565b600480546040516312d9a6ad60e01b81529182018390523360248301526001600160a01b0316906312d9a6ad906044015f6040518083038186803b1580156129d7575f80fd5b505afa1580156129e9573d5f803e3d5ffd5b505050506129f682612b34565b5050565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301525f919084169063dd62ed3e90604401602060405180830381865afa158015612a47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a6b9190613489565b90505f612a79825f196134df565b90508015612323576123236001600160a01b0385168483612bdf565b806020015160405180606001604052806027815260200161392160279139906129f65760405162461bcd60e51b815260040161044491906134cd565b6040516001600160a01b03831660248201526044810182905261118390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612c89565b60408051808201909152600f81526e496e76616c6964206164647265737360881b60208201526001600160a01b038216612b815760405162461bcd60e51b815260040161044491906134cd565b506005546040516001600160a01b0380841692169033907f23c12d5579081c5f1077c04a6b1c114d0f3de239e81a436836d30ecb099ffa13905f90a4600580546001600160a01b0319166001600160a01b0392909216919091179055565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301525f919085169063dd62ed3e90604401602060405180830381865afa158015612c2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c509190613489565b90506123238463095ea7b360e01b85612c6986866134b4565b6040516001600160a01b0390921660248301526044820152606401612afd565b5f612cdd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612d5c9092919063ffffffff16565b905080515f1480612cfd575080806020019051810190612cfd9190613607565b6111835760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610444565b60606107fa84845f85855f80866001600160a01b03168587604051612d819190613747565b5f6040518083038185875af1925050503d805f8114612dbb576040519150601f19603f3d011682016040523d82523d5f602084013e612dc0565b606091505b50915091506116d78783838760608315612e3a5782515f03612e33576001600160a01b0385163b612e335760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610444565b50816107fa565b6107fa8383815115612e4f5781518083602001fd5b8060405162461bcd60e51b815260040161044491906134cd565b5f60208284031215612e79575f80fd5b81356001600160e01b031981168114612e90575f80fd5b9392505050565b6001600160a01b0381168114612eab575f80fd5b50565b8035612eb981612e97565b919050565b5f60208284031215612ece575f80fd5b8135612e9081612e97565b5f8083601f840112612ee9575f80fd5b5081356001600160401b03811115612eff575f80fd5b602083019150836020828501011115612f16575f80fd5b9250929050565b5f805f8060608587031215612f30575f80fd5b8435612f3b81612e97565b93506020850135925060408501356001600160401b03811115612f5c575f80fd5b612f6887828801612ed9565b95989497509550505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715612fb057612fb0612f74565b604052919050565b5f8060408385031215612fc9575f80fd5b8235612fd481612e97565b91506020838101356001600160401b0380821115612ff0575f80fd5b818601915086601f830112613003575f80fd5b81358181111561301557613015612f74565b8060051b9150613026848301612f88565b818152918301840191848101908984111561303f575f80fd5b938501935b83851015613069578435925061305983612e97565b8282529385019390850190613044565b8096505050505050509250929050565b5f60208284031215613089575f80fd5b5035919050565b8015158114612eab575f80fd5b8035612eb981613090565b5f80604083850312156130b9575f80fd5b82356130c481612e97565b915060208301356130d481613090565b809150509250929050565b5f805f80606085870312156130f2575f80fd5b84356130fd81612e97565b935060208501356001600160401b03811115613117575f80fd5b61312387828801612ed9565b909450925050604085013561313781613090565b939692955090935050565b5f805f60608486031215613154575f80fd5b83356001600160401b038082111561316a575f80fd5b818601915086601f83011261317d575f80fd5b813560208282111561319157613191612f74565b6131a3601f8301601f19168201612f88565b925081835288818386010111156131b8575f80fd5b81818501828501375f8183850101528296506131d5818901612eae565b9550505050506131e76040850161309d565b90509250925092565b5f5b8381101561320a5781810151838201526020016131f2565b50505f910152565b5f81518084526132298160208601602086016131f0565b601f01601f19169290920160200192915050565b5f8151608084526132516080850182613212565b90506020830151151560208501526040830151151560408501526060830151151560608501528091505092915050565b602081525f612e90602083018461323d565b5f80602083850312156132a4575f80fd5b82356001600160401b03808211156132ba575f80fd5b818501915085601f8301126132cd575f80fd5b8135818111156132db575f80fd5b8660208260051b85010111156132ef575f80fd5b60209290920196919550909350505050565b5f815180845260208085019450602084015f5b838110156133395781516001600160a01b031687529582019590820190600101613314565b509495945050505050565b5f815180845260208085019450602084015f5b8381101561333957815187529582019590820190600101613357565b60e080825288519082018190525f90610100600582901b8401810191908401906020808d01855b838110156133c85760ff198887030185526133b6868351613212565b9550938201939082019060010161339a565b505050505082810360208401526133df818a613301565b905082810360408401526133f38189613344565b905082810360608401526134078188613344565b6080840196909652505060a081019290925260c090910152949350505050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b8281101561347c57603f1988860301845261346a85835161323d565b9450928501929085019060010161344e565b5092979650505050505050565b5f60208284031215613499575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156134c7576134c76134a0565b92915050565b602081525f612e906020830184613212565b818103818111156134c7576134c76134a0565b600181811c9082168061350657607f821691505b60208210810361292257634e487b7160e01b5f52602260045260245ffd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201525f613573606083018486613524565b9695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f600182016135a2576135a26134a0565b5060010190565b602081525f612e906020830184613301565b5f816135c9576135c96134a0565b505f190190565b6001600160a01b03851681526060602082018190525f906135f49083018587613524565b9050821515604083015295945050505050565b5f60208284031215613617575f80fd5b8151612e9081613090565b5f60208284031215613632575f80fd5b8151612e9081612e97565b601f82111561118357805f5260205f20601f840160051c810160208510156136625750805b601f840160051c820191505b81811015613681575f815560010161366e565b5050505050565b81516001600160401b038111156136a1576136a1612f74565b6136b5816136af84546134f2565b8461363d565b602080601f8311600181146136e8575f84156136d15750858301515b5f19600386901b1c1916600185901b17855561373f565b5f85815260208120601f198616915b82811015613716578886015182559484019460019091019084016136f7565b508582101561373357878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f82516137588184602087016131f0565b9190910192915050565b5f8235609e19833603018112613758575f80fd5b634e487b7160e01b5f52602160045260245ffd5b5f6020828403121561379a575f80fd5b813560048110612e90575f80fd5b5f808335601e198436030181126137bd575f80fd5b8301803591506001600160401b038211156137d6575f80fd5b602001915036819003821315612f16575f80fdfe4d656c644661726d696e674d616e616765723a204164617074657220616c7265616479206578697374734d656c644661726d696e674d616e616765723a20416d6f756e74206d69736d617463684d656c644661726d696e674d616e616765723a204164617074657220646f6573206e6f742065786973744d656c644661726d696e674d616e616765723a204e6f7420656e6f7567682066756e64734d656c644661726d696e674d616e616765723a204164617074657220646f6573206e6f7420696d706c656d656e7420494d656c644661726d696e674d656c644661726d696e674d616e616765723a204e6f20616461707465727320636f6e666967757265644d656c644661726d696e674d616e616765723a204f6e6c79206272696467652063616e2063616c6c20746869732066756e6374696f6e4d656c644661726d696e674d616e616765723a20416461707465722069732064697361626c65644d656c644661726d696e674d616e616765723a20496e76616c696420616461707465722049444d656c644661726d696e674d616e616765723a20496e76616c69642061646170746572204d656c644661726d696e674d616e616765722061646472657373a26469706673582212205ee36ba130fb8af85ab458a0a570c8006f53cfae391a19a35fc832c709683d8364736f6c63430008180033000000000000000000000000dede0a940b388b236f65722734a56e03b79e1c16000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000303b3d643753b86f2045f08b1df0f910f42cb200

Deployed Bytecode

0x6080604052600436106101d3575f3560e01c8063799549ee116100fd578063c3de453d11610092578063dd84dc4c11610062578063dd84dc4c14610615578063e798646614610634578063f23a6e6114610653578063f89d699d1461067f575f80fd5b8063c3de453d1461058a578063ca15c873146105a9578063ce0fa5a9146105c8578063d547741f146105f6575f80fd5b8063a217fddf116100cd578063a217fddf1461050e578063abb50b1514610521578063b12ed45e14610529578063bc197c811461055c575f80fd5b8063799549ee146104925780639010d07c146104b157806390541601146104d057806391d14854146104ef575f80fd5b8063490b48f81161017357806368c4ac261161014357806368c4ac26146103ee578063708b0dbe1461041c57806374f8663b146104535780637846d1e414610473575f80fd5b8063490b48f81461035e5780634d388227146103915780635231f6ce146103b057806367f4a8f0146103cf575f80fd5b8063150b7a02116101ae578063150b7a02146102a0578063248a9ca3146102e45780632f2ff15d1461032057806336568abe1461033f575f80fd5b806301ffc9a71461022e5780630919a7891461026257806312d9a6ad14610281575f80fd5b3661022a57600454604080516080810190915260468082526001600160a01b03909216331491612ac06020830139906102285760405162461bcd60e51b815260040161021f919061214d565b60405180910390fd5b005b5f80fd5b348015610239575f80fd5b5061024d61024836600461217f565b61069c565b60405190151581526020015b60405180910390f35b34801561026d575f80fd5b5061022861027c3660046121c1565b6106c6565b34801561028c575f80fd5b5061022861029b36600461220a565b6108c6565b3480156102ab575f80fd5b506102cb6102ba366004612279565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610259565b3480156102ef575f80fd5b506103126102fe3660046122e3565b5f9081526020819052604090206001015490565b604051908152602001610259565b34801561032b575f80fd5b5061022861033a36600461220a565b6108d4565b34801561034a575f80fd5b5061022861035936600461220a565b6108fd565b348015610369575f80fd5b506103127fccc64574297998b6c3edf6078cc5e01268465ff116954e3af02ff3a70a730f4681565b34801561039c575f80fd5b506102286103ab3660046122fa565b610977565b3480156103bb575f80fd5b506102286103ca366004612322565b610a7f565b3480156103da575f80fd5b506102286103e93660046124d9565b610c2e565b3480156103f9575f80fd5b5061024d610408366004612595565b60026020525f908152604090205460ff1681565b348015610427575f80fd5b5060045461043b906001600160a01b031681565b6040516001600160a01b039091168152602001610259565b34801561045e575f80fd5b506103125f80516020612b8183398151915281565b34801561047e575f80fd5b5061022861048d3660046125ae565b610d2a565b34801561049d575f80fd5b506102286104ac366004612641565b610df9565b3480156104bc575f80fd5b5061043b6104cb366004612671565b610f50565b3480156104db575f80fd5b506102286104ea366004612691565b610f6e565b3480156104fa575f80fd5b5061024d61050936600461220a565b611065565b348015610519575f80fd5b506103125f81565b61022861108d565b348015610534575f80fd5b506103127f969e743677c83a4458df4afcef9c1049579c1137c04e48694290c3e5fe6ef47681565b348015610567575f80fd5b506102cb610576366004612747565b63bc197c8160e01b98975050505050505050565b348015610595575f80fd5b506102286105a43660046122fa565b611373565b3480156105b4575f80fd5b506103126105c33660046122e3565b6114ee565b3480156105d3575f80fd5b5061024d6105e23660046122e3565b60036020525f908152604090205460ff1681565b348015610601575f80fd5b5061022861061036600461220a565b611504565b348015610620575f80fd5b5061022861062f3660046127fa565b611528565b34801561063f575f80fd5b5061022861064e366004612868565b61188a565b34801561065e575f80fd5b506102cb61066d3660046127fa565b63f23a6e6160e01b9695505050505050565b34801561068a575f80fd5b506005546001600160a01b031661043b565b5f6001600160e01b03198216630271189760e51b14806106c057506106c08261190d565b92915050565b5f80516020612b818339815191526106dd81611931565b6001600160a01b0386165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915287919060ff1661073d5760405162461bcd60e51b815260040161021f919061214d565b505f83815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915284919060ff16156107a45760405162461bcd60e51b815260040161021f919061214d565b50845f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b815250906107ee5760405162461bcd60e51b815260040161021f919061214d565b50604051637921219560e11b81526001600160a01b038a169063f242432a906108219030908c908c908c9060040161289d565b5f604051808303815f87803b158015610838575f80fd5b505af115801561084a573d5f803e3d5ffd5b5050505f8681526003602052604090819020805460ff19166001179055518691506001600160a01b03808b1691908c16907fcd3cdba2c4a7a9fa5e8a62dd4a9567275257353804d0b4250b8416cbf6ca5201906108b3908c908c90918252602082015260400190565b60405180910390a4505050505050505050565b6108d0828261193e565b5050565b5f828152602081905260409020600101546108ee81611931565b6108f88383611997565b505050565b6001600160a01b038116331461096d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b606482015260840161021f565b6108d082826119b8565b6001600160a01b0382165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915283919060ff166109d75760405162461bcd60e51b815260040161021f919061214d565b50604051632142170760e11b8152336004820152306024820152604481018390526001600160a01b038416906342842e0e906064015f604051808303815f87803b158015610a23575f80fd5b505af1158015610a35573d5f803e3d5ffd5b50506040518481526001600160a01b03861692503391507f56000d41ed570386e6cbb91e291a2c55110aac38c413ee75bbfe7c9ce5104b0a906020015b60405180910390a3505050565b5f80516020612b81833981519152610a9681611931565b6001600160a01b0385165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915286919060ff16610af65760405162461bcd60e51b815260040161021f919061214d565b505f83815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915284919060ff1615610b5d5760405162461bcd60e51b815260040161021f919061214d565b50604051632142170760e11b81523060048201526001600160a01b038781166024830152604482018790528816906342842e0e906064015f604051808303815f87803b158015610bab575f80fd5b505af1158015610bbd573d5f803e3d5ffd5b5050505f8581526003602052604090819020805460ff19166001179055518591506001600160a01b0380891691908a16907fce160f8f7991700e359926e01fdd784c1991356d33ae3809a305e4eec088bc5d90610c1d908a815260200190565b60405180910390a450505050505050565b83518551148015610c40575082518451145b8015610c4c5750825181145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610c975760405162461bcd60e51b815260040161021f919061214d565b505f5b8551811015610d2157610d1987878381518110610cb957610cb96128d4565b6020026020010151878481518110610cd357610cd36128d4565b6020026020010151878581518110610ced57610ced6128d4565b6020026020010151878787818110610d0757610d076128d4565b905060200281019061062f91906128e8565b600101610c9a565b50505050505050565b81518351148015610d3c575080518251145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610d875760405162461bcd60e51b815260040161021f919061214d565b505f5b8351811015610df257610dea85858381518110610da957610da96128d4565b6020026020010151858481518110610dc357610dc36128d4565b6020026020010151858581518110610ddd57610ddd6128d4565b6020026020010151610a7f565b600101610d8a565b5050505050565b6001600160a01b0383165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915284919060ff16610e595760405162461bcd60e51b815260040161021f919061214d565b50815f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b81525090610ea35760405162461bcd60e51b815260040161021f919061214d565b50604051637921219560e11b81526001600160a01b0386169063f242432a90610ed690339030908990899060040161289d565b5f604051808303815f87803b158015610eed575f80fd5b505af1158015610eff573d5f803e3d5ffd5b505060408051878152602081018790526001600160a01b03891693503392507f83ab655dce8564238f4015e1e43bccfe0fc818637dbe61a3c6223770a773c821910160405180910390a35050505050565b5f828152600160205260408120610f6790836119d9565b9392505050565b82518451148015610f80575080518351145b8015610f8d575081518351145b60405180604001604052806014815260200173092dcecc2d8d2c840c2e4e4c2f240d8cadccee8d60631b81525090610fd85760405162461bcd60e51b815260040161021f919061214d565b505f5b845181101561105d5761105586868381518110610ffa57610ffa6128d4565b6020026020010151868481518110611014576110146128d4565b602002602001015186858151811061102e5761102e6128d4565b6020026020010151868681518110611048576110486128d4565b60200260200101516106c6565b600101610fdb565b505050505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8052600260209081527fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b546040805160608101909152603180825260ff90921692909190612b3090830139906110f75760405162461bcd60e51b815260040161021f919061214d565b5060408051808201909152600e81526d125b9d985b1a5908185b5bdd5b9d60921b60208201523461113b5760405162461bcd60e51b815260040161021f919061214d565b50600480546040516370a0823160e01b815230928101929092526001600160a01b0316905f9082906370a0823190602401602060405180830381865afa158015611187573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ab919061292b565b9050816001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b1580156111e6575f80fd5b505af11580156111f8573d5f803e3d5ffd5b505050505080346112099190612956565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561124b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061126f919061292b565b146040518060600160405280602a8152602001612b06602a9139906112a75760405162461bcd60e51b815260040161021f919061214d565b506005546004546112c5916001600160a01b039182169116346119e4565b60055460048054604051630937b85760e31b81526001600160a01b0391821692810192909252346024830152606060448301525f6064830152909116906349bdc2b8906084015f604051808303815f87803b158015611322575f80fd5b505af1158015611334573d5f803e3d5ffd5b50506040513481525f92503391507f8e45dd3e0559b56feca4f095454c145dbe2acb06c789c0486fe2b0f1e609a0019060200160405180910390a35050565b6001600160a01b0382165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915283919060ff166113d35760405162461bcd60e51b815260040161021f919061214d565b50815f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b8152509061141d5760405162461bcd60e51b815260040161021f919061214d565b5060055461143a906001600160a01b038681169133911686611a47565b600554604051630937b85760e31b81526001600160a01b03868116600483015260248201869052606060448301525f6064830152909116906349bdc2b8906084015f604051808303815f87803b158015611492575f80fd5b505af11580156114a4573d5f803e3d5ffd5b50506040518581526001600160a01b03871692503391507f8e45dd3e0559b56feca4f095454c145dbe2acb06c789c0486fe2b0f1e609a0019060200160405180910390a350505050565b5f8181526001602052604081206106c090611a85565b5f8281526020819052604090206001015461151e81611931565b6108f883836119b8565b5f80516020612b8183398151915261153f81611931565b6001600160a01b0387165f90815260026020908152604091829020548251808401909352601683525f80516020612b618339815191529183019190915288919060ff1661159f5760405162461bcd60e51b815260040161021f919061214d565b505f85815260036020908152604091829020548251808401909352601983527814995c5d595cdd08185b1c9958591e481c1c9bd8d95cdcd959603a1b9183019190915286919060ff16156116065760405162461bcd60e51b815260040161021f919061214d565b50865f81116040518060400160405280600e81526020016d125b9d985b1a5908185b5bdd5b9d60921b815250906116505760405162461bcd60e51b815260040161021f919061214d565b506001600160a01b038a1661178857600554600480546040516331f0926560e01b81526001600160a01b03938416936331f092659361169993909116918d918c918c9101612991565b6020604051808303815f875af11580156116b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116d9919061292b565b506005546004546116f8916001600160a01b039182169116308b611a47565b60048054604051632e1a7d4d60e01b81529182018a90526001600160a01b031690632e1a7d4d906024015f604051808303815f87803b158015611739575f80fd5b505af115801561174b573d5f803e3d5ffd5b50506040516001600160a01b038c1692508a156108fc0291508a905f818181858888f19350505050158015611782573d5f803e3d5ffd5b5061181a565b6005546040516331f0926560e01b81526001600160a01b03909116906331f09265906117be908d908c908b908b90600401612991565b6020604051808303815f875af11580156117da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117fe919061292b565b5060055461181a906001600160a01b038c811691168b8b611a47565b5f8781526003602052604090819020805460ff191660011790555187906001600160a01b03808c1691908d16907f0d926ad85030030cad809df6a05eb364038b87665b35bee01a3656889901116f90611876908d815260200190565b60405180910390a450505050505050505050565b7f969e743677c83a4458df4afcef9c1049579c1137c04e48694290c3e5fe6ef4766118b481611931565b6001600160a01b0383165f81815260026020908152604091829020805460ff1916861515908117909155915191825233917f9db3eb580aece44728f5d3f04a2a246f883906d2391124024cfd10c5d338b5ba9101610a72565b5f6001600160e01b03198216635a05180f60e01b14806106c057506106c082611a8e565b61193b813361193e565b50565b6119488282611065565b6108d05761195581611ac2565b611960836020611ad4565b6040516020016119719291906129c2565b60408051601f198184030181529082905262461bcd60e51b825261021f9160040161214d565b6119a18282611c6a565b5f8281526001602052604090206108f89082611ced565b6119c28282611d01565b5f8281526001602052604090206108f89082611d65565b5f610f678383611d79565b6040516001600160a01b0383166024820152604481018290526108f890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611d9f565b6040516001600160a01b0380851660248301528316604482015260648101829052611a7f9085906323b872dd60e01b90608401611a10565b50505050565b5f6106c0825490565b5f6001600160e01b03198216637965db0b60e01b14806106c057506301ffc9a760e01b6001600160e01b03198316146106c0565b60606106c06001600160a01b03831660145b60605f611ae2836002612a36565b611aed906002612956565b67ffffffffffffffff811115611b0557611b05612361565b6040519080825280601f01601f191660200182016040528015611b2f576020820181803683370190505b509050600360fc1b815f81518110611b4957611b496128d4565b60200101906001600160f81b03191690815f1a905350600f60fb1b81600181518110611b7757611b776128d4565b60200101906001600160f81b03191690815f1a9053505f611b99846002612a36565b611ba4906001612956565b90505b6001811115611c1b576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611bd857611bd86128d4565b1a60f81b828281518110611bee57611bee6128d4565b60200101906001600160f81b03191690815f1a90535060049490941c93611c1481612a4d565b9050611ba7565b508315610f675760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161021f565b611c748282611065565b6108d0575f828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611ca93390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f610f67836001600160a01b038416611e72565b611d0b8282611065565b156108d0575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f610f67836001600160a01b038416611ebe565b5f825f018281548110611d8e57611d8e6128d4565b905f5260205f200154905092915050565b5f611df3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611fa19092919063ffffffff16565b905080515f1480611e13575080806020019051810190611e139190612a62565b6108f85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161021f565b5f818152600183016020526040812054611eb757508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556106c0565b505f6106c0565b5f8181526001830160205260408120548015611f98575f611ee0600183612a7d565b85549091505f90611ef390600190612a7d565b9050818114611f52575f865f018281548110611f1157611f116128d4565b905f5260205f200154905080875f018481548110611f3157611f316128d4565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080611f6357611f63612a90565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506106c0565b5f9150506106c0565b6060611faf84845f85611fb7565b949350505050565b6060824710156120185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161021f565b5f80866001600160a01b031685876040516120339190612aa4565b5f6040518083038185875af1925050503d805f811461206d576040519150601f19603f3d011682016040523d82523d5f602084013e612072565b606091505b50915091506120838783838761208e565b979650505050505050565b606083156120fc5782515f036120f5576001600160a01b0385163b6120f55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161021f565b5081611faf565b611faf83838151156121115781518083602001fd5b8060405162461bcd60e51b815260040161021f919061214d565b5f5b8381101561214557818101518382015260200161212d565b50505f910152565b602081525f825180602084015261216b81604085016020870161212b565b601f01601f19169190910160400192915050565b5f6020828403121561218f575f80fd5b81356001600160e01b031981168114610f67575f80fd5b80356001600160a01b03811681146121bc575f80fd5b919050565b5f805f805f60a086880312156121d5575f80fd5b6121de866121a6565b94506121ec602087016121a6565b94979496505050506040830135926060810135926080909101359150565b5f806040838503121561221b575f80fd5b8235915061222b602084016121a6565b90509250929050565b5f8083601f840112612244575f80fd5b50813567ffffffffffffffff81111561225b575f80fd5b602083019150836020828501011115612272575f80fd5b9250929050565b5f805f805f6080868803121561228d575f80fd5b612296866121a6565b94506122a4602087016121a6565b935060408601359250606086013567ffffffffffffffff8111156122c6575f80fd5b6122d288828901612234565b969995985093965092949392505050565b5f602082840312156122f3575f80fd5b5035919050565b5f806040838503121561230b575f80fd5b612314836121a6565b946020939093013593505050565b5f805f8060808587031215612335575f80fd5b61233e856121a6565b935061234c602086016121a6565b93969395505050506040820135916060013590565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561239e5761239e612361565b604052919050565b5f67ffffffffffffffff8211156123bf576123bf612361565b5060051b60200190565b5f82601f8301126123d8575f80fd5b813560206123ed6123e8836123a6565b612375565b8083825260208201915060208460051b87010193508684111561240e575f80fd5b602086015b8481101561243157612424816121a6565b8352918301918301612413565b509695505050505050565b5f82601f83011261244b575f80fd5b8135602061245b6123e8836123a6565b8083825260208201915060208460051b87010193508684111561247c575f80fd5b602086015b848110156124315780358352918301918301612481565b5f8083601f8401126124a8575f80fd5b50813567ffffffffffffffff8111156124bf575f80fd5b6020830191508360208260051b8501011115612272575f80fd5b5f805f805f8060a087890312156124ee575f80fd5b6124f7876121a6565b9550602087013567ffffffffffffffff80821115612513575f80fd5b61251f8a838b016123c9565b96506040890135915080821115612534575f80fd5b6125408a838b0161243c565b95506060890135915080821115612555575f80fd5b6125618a838b0161243c565b94506080890135915080821115612576575f80fd5b5061258389828a01612498565b979a9699509497509295939492505050565b5f602082840312156125a5575f80fd5b610f67826121a6565b5f805f80608085870312156125c1575f80fd5b6125ca856121a6565b9350602085013567ffffffffffffffff808211156125e6575f80fd5b6125f2888389016123c9565b94506040870135915080821115612607575f80fd5b6126138883890161243c565b93506060870135915080821115612628575f80fd5b506126358782880161243c565b91505092959194509250565b5f805f60608486031215612653575f80fd5b61265c846121a6565b95602085013595506040909401359392505050565b5f8060408385031215612682575f80fd5b50508035926020909101359150565b5f805f805f60a086880312156126a5575f80fd5b6126ae866121a6565b9450602086013567ffffffffffffffff808211156126ca575f80fd5b6126d689838a016123c9565b955060408801359150808211156126eb575f80fd5b6126f789838a0161243c565b9450606088013591508082111561270c575f80fd5b61271889838a0161243c565b9350608088013591508082111561272d575f80fd5b5061273a8882890161243c565b9150509295509295909350565b5f805f805f805f8060a0898b03121561275e575f80fd5b612767896121a6565b975061277560208a016121a6565b9650604089013567ffffffffffffffff80821115612791575f80fd5b61279d8c838d01612498565b909850965060608b01359150808211156127b5575f80fd5b6127c18c838d01612498565b909650945060808b01359150808211156127d9575f80fd5b506127e68b828c01612234565b999c989b5096995094979396929594505050565b5f805f805f8060a0878903121561280f575f80fd5b612818876121a6565b9550612826602088016121a6565b94506040870135935060608701359250608087013567ffffffffffffffff81111561284f575f80fd5b61258389828a01612234565b801515811461193b575f80fd5b5f8060408385031215612879575f80fd5b612882836121a6565b915060208301356128928161285b565b809150509250929050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a0608082018190525f9082015260c00190565b634e487b7160e01b5f52603260045260245ffd5b5f808335601e198436030181126128fd575f80fd5b83018035915067ffffffffffffffff821115612917575f80fd5b602001915036819003821315612272575f80fd5b5f6020828403121561293b575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106c0576106c0612942565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60018060a01b0385168152836020820152606060408201525f6129b8606083018486612969565b9695505050505050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f83516129f981601785016020880161212b565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612a2a81602884016020880161212b565b01602801949350505050565b80820281158282048414176106c0576106c0612942565b5f81612a5b57612a5b612942565b505f190190565b5f60208284031215612a72575f80fd5b8151610f678161285b565b818103818111156106c0576106c0612942565b634e487b7160e01b5f52603160045260245ffd5b5f8251612ab581846020870161212b565b919091019291505056fe4d656c6442726964676552656365697665723a204f6e6c7920574554482063616e206465706f73697420455448206469726563746c7920746f2074686520636f6e74726163744d656c6442726964676552656365697665723a204e6174697665207772617070696e67206661696c65644d656c6442726964676552656365697665723a204e617469766520546f6b656e206973206e6f7420737570706f72746564546f6b656e206973206e6f7420737570706f7274656400000000000000000000f21a16feb1ed068bfca4f16029f44a27181a38cc067de137a57f47ae74f52a11a26469706673582212205602ce934a24f938602e4872ba1e0da651031a7214f26d78f97271b2f60eee7264736f6c63430008180033

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

000000000000000000000000dede0a940b388b236f65722734a56e03b79e1c16000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000303b3d643753b86f2045f08b1df0f910f42cb200

-----Decoded View---------------
Arg [0] : _defaultAdmin (address): 0xdede0A940B388B236F65722734a56e03B79e1C16
Arg [1] : _wETH (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _treasury (address): 0x303b3D643753b86F2045F08b1dF0f910F42cB200

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000dede0a940b388b236f65722734a56e03b79e1c16
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 000000000000000000000000303b3d643753b86f2045f08b1df0f910f42cb200


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.