Contract 0x9731F8a3B2a9EE5e017483e6b4B62a9aC1af532D

Contract Overview

Balance:
0 ETH

Token:
Txn Hash Method
Block
From
To
Value
0xa06448f7b906233d3fd5d1e44b437a66e885492b4e441c16fdecfe24e7777e8eSend Vouchers87654662023-05-01 16:36:40301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000054876243962 ETH0.0026584228977.50000025
0x1f79822f671b9c80ef52889de66fef716b1c36f3cb00d2f594bf8201cd43a4bcSend Vouchers87654632023-05-01 16:36:34301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.001357257607374 ETH0.0026586360417.50000025
0x67ca35d88f5fa346783be2751928c8b46d5a5c2daf98fc55e07d28cc14260811Send Vouchers87654592023-05-01 16:36:26301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.002551644288255 ETH0.0026621802417.50000025
0x9eddcb94faad2364e200ab725060f83e0d223ea210f20577d7c8a29f1f489a5cSend Vouchers87654552023-05-01 16:36:18301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.001279857645349 ETH0.0026621802417.50000025
0x826aade01bf9749192fad376a5ea06ae6a6c514d045d8286a4d9162c88e314b9Send Vouchers87654522023-05-01 16:36:12301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.00048073266361 ETH0.0027013752427.50000025
0x751ed6b4e013f923bc3191e2b1d50bd52ab4665abecbffbf997b08354afe55f4Send Vouchers87654482023-05-01 16:36:04301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000054344620109 ETH0.0026532889587.50000025
0x75692b1021ba576b245c2f4c9cbd947a66f1a53d3ac9149b925341ec98181363Send Vouchers87654442023-05-01 16:35:56301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.00028374847314 ETH0.0026533476457.50000025
0x59155169f51868d82cae486dc7ab093386cac2e5a286d4881f9ea7fb66c85da4Send Vouchers87654412023-05-01 16:35:50301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.001957112553506 ETH0.0026574714327.50000025
0x88e84f4dc76eccfa43fbc1e17bd533bc5610f887ec13f0338a7548a809c67111Send Vouchers87654372023-05-01 16:35:42301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.010821533422555 ETH0.0026644882217.50000025
0xcbfff6d72417079741007ca91272ed60d16ee3ad54bdddadd7028cf9bae16f54Send Vouchers87654332023-05-01 16:35:34301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000055500588853 ETH0.002664231667.50000025
0xebe70c24ba542fe673b636b7994dbc8eb8669c52ca2f098af11bab6d1561cb22Deposit87654302023-05-01 16:35:28301 days 20 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.0037621406947.50000025
0xc2366284a52eec8e4dc53f56441836ead31a4d886a5801ea403cf2097a14b63eActivate Chain P...87610242023-05-01 14:08:36301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.0167217788187.50000625
0xc276d1891cb558836ca0dcb2721d56b8afac8b4a402b367b42a561bb4caa933aActivate Chain P...87610212023-05-01 14:08:30301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.0167217788187.50000625
0xf37001e21f16023a5b83454050282e4d3f506a24f87b69a637b880403efa1c67Activate Chain P...87610182023-05-01 14:08:24301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016751649215187.50000625
0x353944ba2270128f26d1dec854c23ceec2b56608ccbcbf01251d2eee2c0e46c5Activate Chain P...87610142023-05-01 14:08:16301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016750545643187.50000625
0xd0914570594981d972b906ebdd2cbf67b1225600878397667f7f15a9be6b53d4Activate Chain P...87610112023-05-01 14:08:10301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016786036753187.50000625
0xc418b174756902fb1d84dbad089964375984c5308240719a4a7b1d629393336bActivate Chain P...87610082023-05-01 14:08:04301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016784837036187.50000625
0x038c296ee4275a51a21ec22243bec0a9f0bef92501dcc29b084d50c594e021d7Activate Chain P...87610042023-05-01 14:07:56301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016831032889187.50000625
0x742b1062d46251475498c3cb9d7c3d32039c98456ef7456e5d7974f1438965b8Activate Chain P...87610012023-05-01 14:07:50301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016832362127187.50000625
0xa224b13d5ebe510cc89c842578184b53d6914906c067239a8a0344daa06c114cActivate Chain P...87609972023-05-01 14:07:42301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016832362127187.50000625
0xfff31678450567220a8a9143346c57bee9f6e4a5f96b0161b8788190c1234e27Activate Chain P...87609942023-05-01 14:07:36301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.016832362127187.50000625
0x99986c519dba05fcd69c8b10e2288414f2545dcb07ab4a0dc1be38548819cc08Activate Chain P...87609902023-05-01 14:07:28301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.015969657861187.50000625
0xcaeaeaa91ec2d7aecfa8a835a0b69c2c385a389e23b22a6e9a4712cbd054585cCreate Chain Pat...87609872023-05-01 14:07:22301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.056523271794187.50000625
0x65d387099a7d3ecdf7608420fe5f128bc9192dd30780138400abf803251d40f8Create Chain Pat...87609832023-05-01 14:07:14301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.0110850452837.50000125
0xe08e8e6ccc61c0681fdaefc4f2510b1af35e737ef207901ab4e6a7338c34f1b9Create Chain Pat...87609802023-05-01 14:07:08301 days 22 hrs ago0x256fdf96349a412a97bc9b0d21519ec19232816f IN 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0 ETH0.01047811266737.50000125
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x04af2efde10896e5d815ea7e4f135e1f9fa5af53ede43969fab84df3955bf77d212856332024-02-15 12:15:3412 days 33 mins ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000438344059864876 ETH
0x04af2efde10896e5d815ea7e4f135e1f9fa5af53ede43969fab84df3955bf77d212856332024-02-15 12:15:3412 days 33 mins ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000438344059864876 ETH
0x00602c813224e0b25e165d91aeb760a3ee905f0562592b9eb0ac415d534b73bc212841542024-02-15 11:26:1612 days 1 hr ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004171704036027 ETH
0x00602c813224e0b25e165d91aeb760a3ee905f0562592b9eb0ac415d534b73bc212841542024-02-15 11:26:1612 days 1 hr ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000004171704036027 ETH
0x676cd0caa860b829c5d3ed12b20f954f91c5f6fab094f4d7a16dbe2703aeee5b212788092024-02-15 8:28:0612 days 4 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.00000386208708819 ETH
0x676cd0caa860b829c5d3ed12b20f954f91c5f6fab094f4d7a16dbe2703aeee5b212788092024-02-15 8:28:0612 days 4 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.00000386208708819 ETH
0x248341008e29f7856609df81452eefd1e9762ea82b77b0a6f64366ff252ef031212787922024-02-15 8:27:3212 days 4 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000438344059864876 ETH
0x248341008e29f7856609df81452eefd1e9762ea82b77b0a6f64366ff252ef031212787922024-02-15 8:27:3212 days 4 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000438344059864876 ETH
0xf0ab6dfa8b0e025ba7e7520785933ceb477ab2b26284a0919a4871cfc7e2834e212787712024-02-15 8:26:5012 days 4 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004171704036027 ETH
0xf0ab6dfa8b0e025ba7e7520785933ceb477ab2b26284a0919a4871cfc7e2834e212787712024-02-15 8:26:5012 days 4 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000004171704036027 ETH
0x95e2fa672a28cb0631ef93e55b8751c9254be054352e0133eae413658392519f212787482024-02-15 8:26:0412 days 4 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000699440190410745 ETH
0x95e2fa672a28cb0631ef93e55b8751c9254be054352e0133eae413658392519f212787482024-02-15 8:26:0412 days 4 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000699440190410745 ETH
0xaedd64b7624796567ca6fae1847832a3cffacc12e481e8475c20eb0fb6451dbc212681122024-02-15 2:31:3212 days 10 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000699440190410745 ETH
0xaedd64b7624796567ca6fae1847832a3cffacc12e481e8475c20eb0fb6451dbc212681122024-02-15 2:31:3212 days 10 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000699440190410745 ETH
0x6645dcbe5e1d1bcd801a2181bdff00db83e34135e968db8be9d60a4295764d05212677292024-02-15 2:18:4612 days 10 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004172549421662 ETH
0x6645dcbe5e1d1bcd801a2181bdff00db83e34135e968db8be9d60a4295764d05212677292024-02-15 2:18:4612 days 10 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000004172549421662 ETH
0x3ed8a44da2775089b31bbf1c571ff1c4f1812f7ea3f6f174c16a229ceca796cb212615822024-02-14 22:53:5212 days 13 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004180110323204 ETH
0x3ed8a44da2775089b31bbf1c571ff1c4f1812f7ea3f6f174c16a229ceca796cb212615822024-02-14 22:53:5212 days 13 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000004180110323204 ETH
0x87cd30be067449a8d13c6f4db300ed5cc1e3c6c7198452d836deb1e89e9656a9212479762024-02-14 15:20:2012 days 21 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000699440190410745 ETH
0x87cd30be067449a8d13c6f4db300ed5cc1e3c6c7198452d836deb1e89e9656a9212479762024-02-14 15:20:2012 days 21 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000699440190410745 ETH
0xdf4456634c371061361ae0f44a38c46ee461aeb0f671f751d8b2e5ae896b4982212455572024-02-14 13:59:4212 days 22 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004181041627936 ETH
0xdf4456634c371061361ae0f44a38c46ee461aeb0f671f751d8b2e5ae896b4982212455572024-02-14 13:59:4212 days 22 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000004181041627936 ETH
0x31f4795842a70435f12f3f9ba719b31821555af6c3b0ab7030caf6e5b0879a5d212453932024-02-14 13:54:1412 days 22 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000438344059864876 ETH
0x31f4795842a70435f12f3f9ba719b31821555af6c3b0ab7030caf6e5b0879a5d212453932024-02-14 13:54:1412 days 22 hrs ago 0x76303b0c86ec887867e22e44a681bdbcae85ccdf0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0.000438344059864876 ETH
0xc580e854b6760bcdfa3aaffbf2a238469a1a17f272d16a60ce60ab6d271d75be212452512024-02-14 13:49:3012 days 22 hrs ago 0x9731f8a3b2a9ee5e017483e6b4b62a9ac1af532d0xbec70f2e023c823442cf2d21b95ea21ff75752670.000004181041627936 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AssetRouter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion, MIT license
File 1 of 23 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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:
 *
 * ```
 * 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}:
 *
 * ```
 * 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.
 */
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 2 of 23 : 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 3 of 23 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 4 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.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 5 of 23 : 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 6 of 23 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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.
 */
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].
     */
    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 7 of 23 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-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;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    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));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    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");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    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");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 8 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return 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 9 of 23 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 10 of 23 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.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 `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);
    }
}

File 11 of 23 : 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 12 of 23 : 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 13 of 23 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 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 10, 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 * 8) < value ? 1 : 0);
        }
    }
}

File 14 of 23 : AssetRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IFeeHandler.sol";
import "./interfaces/IAssetRouter.sol";
import "./interfaces/IAssetV2.sol";
import "./interfaces/IBridge.sol";
import "./interfaces/IFeeCollectorV2.sol";
import "hardhat/console.sol";

contract AssetRouter is IAssetRouter, AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE");

    uint256 public constant BP_DENOMINATOR = 10000;

    /// @notice chainpaths per pool poolId=>chainPath
    mapping(uint16 => ChainPath[]) public chainPaths;

    /// @notice bytes of srcPoolId + chainId + dstPoolId => index in the array of chainpaths
    mapping(bytes => uint256) public chainPathIndexLookup;

    /// @notice lookup by poolId => PoolObject
    mapping(uint16 => PoolObject) public poolLookup;

    uint16 public chainId; // local chain id

    mapping(uint16 => uint16[]) public poolIdsPerChain; // ids of pools that are registered on a specific chain

    IFeeHandler public feeHandler; // address for retrieving fee params for swaps
    IFeeCollectorV2 public feeCollector;
    IBridge public bridge;

    uint256 public syncDeviation; // % of deviation accepted for triggering syncing

    event CrossChainSwapInitiated(
        address indexed sender,
        bytes32 id,
        uint16 srcPoolId,
        uint16 dstChainId,
        uint16 dstPoolId,
        uint256 amount,
        uint256 fee,
        uint256 vouchers,
        uint256 optimalDstBandwidth,
        bytes payload
    );
    event CrossChainSwapPerformed(
        uint16 srcPoolId,
        uint16 dstPoolId,
        uint16 srcChainId,
        address to,
        uint256 amount,
        uint256 fee
    );
    event CrossChainLiquidityInitiated(
        address indexed sender,
        bytes32 id,
        uint16 srcPoolId,
        uint16 dstChainId,
        uint16 dstPoolId,
        uint256 vouchers,
        uint256 optimalDstBandwidth
    );
    event CrossChainLiquidityPerformed(LiquidityMessage _message);
    event SendVouchers(uint16 dstChainId, uint16 dstPoolId, uint256 vouchers, uint256 optimalDstBandwidth);
    event VouchersReceived(uint16 chainId, uint16 srcPoolId, uint256 amount, uint256 optimalDstBandwidth);
    event SwapRemote(address to, uint256 amount, uint256 fee);
    event ChainPathUpdate(uint16 dstChainId, uint16 dstPoolId, uint256 weight);
    event FeeHandlerUpdated(address oldFeeHandler, address newFeeHandler);
    event SyncDeviationUpdated(uint256 oldDeviation, uint256 newDeviation);
    event FeeCollected(uint256 fee);

    error InactiveChainPath();
    error ActiveChainPath();
    error UnknownChainPath();
    error InsufficientLiquidity();
    error SlippageTooHigh();
    error SrcBandwidthTooLow();
    error DstBandwidthTooLow();
    error ChainPathExists();
    error FeeLibraryZero();
    error SyncDeviationTooHigh();
    error NotEnoughLiquidity();

    constructor(IFeeHandler _feeHandler, uint16 _chainId, IFeeCollectorV2 _feeCollector) {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setupRole(BRIDGE_ROLE, msg.sender);
        chainId = _chainId;
        feeHandler = _feeHandler;
        feeCollector = _feeCollector;
    }

    function getChainPathsLength(uint16 _poolId) public view returns (uint256) {
        return chainPaths[_poolId].length;
    }

    function swap(SwapParams calldata swapParams) external payable nonReentrant returns (bytes32) {
        ChainPath storage cp = getChainPath(swapParams.srcPoolId, swapParams.dstChainId, swapParams.dstPoolId);
        PoolObject storage pool = poolLookup[swapParams.srcPoolId];
        if (!cp.active) revert InactiveChainPath();
        if (cp.actualKbp <= swapParams.amount) revert InsufficientLiquidity();
        SwapMessage memory swapMessage;
        swapMessage.payload = swapParams.payload;
        (swapMessage.amount, swapMessage.fee) = feeHandler.getFees(
            swapParams.srcPoolId,
            swapParams.amount,
            cp.actualKbp,
            cp.optimalDstBandwidth,
            cp.actualBandwidth,
            (pool.totalLiquidity * cp.weight) / pool.totalWeight
        );

        if (swapMessage.amount <= swapParams.minAmount) revert SlippageTooHigh();
        if (cp.bandwidth <= swapParams.amount) revert SrcBandwidthTooLow();
        if (cp.kbp + cp.vouchers <= swapMessage.amount) revert DstBandwidthTooLow();
        if (cp.bandwidth <= swapMessage.amount) revert DstBandwidthTooLow();

        cp.bandwidth -= swapMessage.amount;
        cp.actualBandwidth -= swapMessage.amount;

        cp.actualKbp += swapMessage.amount;
        pool.undistributedVouchers += swapParams.amount;

        if (pool.undistributedVouchers >= (pool.totalLiquidity * syncDeviation) / BP_DENOMINATOR) {
            _sync(pool);
        }

        (swapMessage.vouchers, swapMessage.optimalDstBandwidth) = _sendVouchersInternal(cp, pool, true);

        IERC20(IAssetV2(pool.poolAddress).token()).safeTransferFrom(msg.sender, pool.poolAddress, swapParams.amount);
        {
            swapMessage.id = keccak256(
                abi.encodePacked(bridge, bridge.nextNonce(swapParams.dstChainId), block.timestamp, MESSAGE_TYPE.SWAP)
            );

            bridge.dispatchMessage{ value: msg.value }(
                swapParams.dstChainId,
                MESSAGE_TYPE.SWAP,
                swapParams.refundAddress,
                abi.encodePacked(
                    MESSAGE_TYPE.SWAP,
                    swapParams.srcPoolId,
                    swapParams.dstPoolId,
                    swapParams.to,
                    swapMessage.amount,
                    swapMessage.fee,
                    swapMessage.vouchers,
                    swapMessage.optimalDstBandwidth,
                    swapMessage.id,
                    swapMessage.payload
                )
            );

            emit CrossChainSwapInitiated(
                msg.sender,
                swapMessage.id,
                swapParams.srcPoolId,
                swapParams.dstChainId,
                swapParams.dstPoolId,
                swapParams.amount,
                swapMessage.fee,
                swapMessage.vouchers,
                swapMessage.optimalDstBandwidth,
                swapMessage.payload
            );

            return swapMessage.id;
        }
    }

    function swapRemote(
        uint16 _srcPoolId,
        uint16 _dstPoolId,
        uint16 _srcChainId,
        address _to,
        uint256 _amount,
        uint256 _fee,
        uint256 _vouchers,
        uint256 _optimalDstBandwidth
    ) external nonReentrant onlyRole(BRIDGE_ROLE) {
        ChainPath storage cp = unsafeGetChainPath(_dstPoolId, _srcChainId, _srcPoolId);
        PoolObject storage pool = poolLookup[_dstPoolId];

        cp.bandwidth += _vouchers;
        if (cp.optimalDstBandwidth != _optimalDstBandwidth) {
            cp.optimalDstBandwidth = _optimalDstBandwidth;
        }
        emit VouchersReceived(_srcChainId, _srcPoolId, _vouchers, _optimalDstBandwidth);

        cp.kbp -= _amount;
        cp.actualKbp -= _amount;
        cp.actualBandwidth += _amount;
        IAssetV2(pool.poolAddress).release(_to, _amount);
        if (_fee > 0 && address(feeCollector) != address(0)) {
            emit FeeCollected(_fee);
            pool.totalLiquidity += _fee;
            // feeCollector.collectFees(_to, _s.fee); // TODO this needs to be implemented
        }
        emit CrossChainSwapPerformed(_srcPoolId, _dstPoolId, _srcChainId, _to, _amount, _fee);
    }

    function sendVouchers(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId,
        address payable _refundAddress
    ) public payable nonReentrant returns (bytes32 id) {
        ChainPath storage cp = getChainPath(_srcPoolId, _dstChainId, _dstPoolId);
        PoolObject storage pool = poolLookup[_srcPoolId];
        (uint256 vouchers, uint256 optimalDstBandwidth) = _sendVouchersInternal(cp, pool, false);
        id = keccak256(
            abi.encodePacked(bridge, bridge.nextNonce(_dstChainId), block.timestamp, MESSAGE_TYPE.ADD_LIQUIDITY)
        );
        bridge.dispatchMessage{ value: msg.value }(
            _dstChainId,
            MESSAGE_TYPE.ADD_LIQUIDITY,
            _refundAddress,
            abi.encodePacked(MESSAGE_TYPE.ADD_LIQUIDITY, _srcPoolId, _dstPoolId, vouchers, optimalDstBandwidth, id)
        );
        emit CrossChainLiquidityInitiated(
            msg.sender,
            id,
            _srcPoolId,
            _dstChainId,
            _dstPoolId,
            vouchers,
            optimalDstBandwidth
        );
    }

    function _sendVouchersInternal(
        ChainPath storage cp,
        PoolObject storage pool,
        bool _swap
    ) internal returns (uint256 vouchers, uint256 optimalDstBandwidth) {
        if (!cp.active) revert InactiveChainPath();

        unchecked {
            cp.kbp += cp.vouchers;
            if (!_swap) cp.actualKbp += cp.vouchers;
            vouchers = cp.vouchers;
            cp.vouchers = 0;
        }
        optimalDstBandwidth = (pool.totalLiquidity * cp.weight) / pool.totalWeight;
    }

    function receiveVouchers(
        uint16 _srcChainId,
        uint16 _srcPoolId,
        uint16 _dstPoolId,
        uint256 _vouchers,
        uint256 _optimalDstBandwidth,
        bool _swap
    ) external nonReentrant onlyRole(BRIDGE_ROLE) {
        ChainPath storage cp = getChainPath(_dstPoolId, _srcChainId, _srcPoolId);

        cp.bandwidth += _vouchers;
        if (!_swap) {
            cp.actualBandwidth += _vouchers;
        }
        if (cp.optimalDstBandwidth != _optimalDstBandwidth) {
            cp.optimalDstBandwidth = _optimalDstBandwidth;
        }
        emit VouchersReceived(_srcChainId, _srcPoolId, _vouchers, _optimalDstBandwidth);
    }

    function deposit(address _to, uint16 _poolId, uint256 _amount) external {
        PoolObject storage pool = poolLookup[_poolId];
        pool.totalLiquidity += _amount;
        pool.undistributedVouchers += _amount;

        _sync(pool);

        IERC20(IAssetV2(pool.poolAddress).token()).safeTransferFrom(msg.sender, pool.poolAddress, _amount);
        IAssetV2(pool.poolAddress).mint(_to, _amount);
    }

    function createChainPath(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId,
        uint16 _weight,
        address _poolAddress
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        uint256 chainPathLength = chainPaths[_srcPoolId].length;
        for (uint256 i; i < chainPathLength; ++i) {
            ChainPath memory cp = chainPaths[_srcPoolId][i];
            bool exists = cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId && cp.srcPoolId == _srcPoolId;
            if (exists) revert ActiveChainPath();
        }
        if (poolLookup[_srcPoolId].poolAddress == address(0)) {
            poolLookup[_srcPoolId] = PoolObject(_srcPoolId, _poolAddress, 0, 0, 0);
        }
        poolLookup[_srcPoolId].totalWeight += _weight;
        chainPathIndexLookup[abi.encodePacked(_srcPoolId, _dstChainId, _dstPoolId)] = chainPaths[_srcPoolId].length;
        chainPaths[_srcPoolId].push(
            ChainPath(false, _srcPoolId, _dstChainId, _dstPoolId, _weight, 0, 0, 0, 0, 0, 0, _poolAddress)
        );
        emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
    }

    function setBridge(IBridge _newBridge) external onlyRole(DEFAULT_ADMIN_ROLE) {
        bridge = _newBridge;
    }

    function setWeightForChainPath(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId,
        uint16 _weight
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        ChainPath storage cp = getChainPath(_srcPoolId, _dstChainId, _dstPoolId);
        PoolObject storage pool = poolLookup[_srcPoolId];
        pool.totalWeight = pool.totalWeight - cp.weight + _weight;
        cp.weight = _weight;
        emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
    }

    function setFeeLibrary(address _feeHandler) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_feeHandler == address(0)) revert FeeLibraryZero();
        emit FeeHandlerUpdated(address(feeHandler), _feeHandler);
        feeHandler = IFeeHandler(_feeHandler);
    }

    function setSyncDeviation(uint256 _syncDeviation) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_syncDeviation > BP_DENOMINATOR) revert SyncDeviationTooHigh();
        emit SyncDeviationUpdated(syncDeviation, _syncDeviation);
        syncDeviation = _syncDeviation;
    }

    function sync(uint16 _poolId) external {
        _sync(poolLookup[_poolId]);
    }

    function activateChainPath(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        ChainPath storage cp = getChainPath(_srcPoolId, _dstChainId, _dstPoolId);
        if (cp.active) revert ActiveChainPath();
        cp.active = true;
        // we check if this pool id was registered in the poolIds if not, we add it
        bool found;
        uint256 poolLengthSrc = poolIdsPerChain[chainId].length;
        uint256 poolLengthDst = poolIdsPerChain[_dstChainId].length;
        for (uint256 i; i < poolLengthSrc; i++) {
            if (poolIdsPerChain[chainId][i] == _srcPoolId) {
                found = true;
            }
        }
        if (!found) {
            poolIdsPerChain[chainId].push(_srcPoolId);
        }

        found = false;
        for (uint256 i; i < poolLengthDst; i++) {
            if (poolIdsPerChain[_dstChainId][i] == _dstPoolId) {
                found = true;
            }
        }
        if (!found) {
            poolIdsPerChain[_dstChainId].push(_dstPoolId);
        }
    }

    function getChainPath(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId
    ) internal view returns (ChainPath storage) {
        ChainPath storage cp = chainPaths[_srcPoolId][
            chainPathIndexLookup[abi.encodePacked(_srcPoolId, _dstChainId, _dstPoolId)]
        ];
        if (cp.dstChainId != _dstChainId) {
            revert UnknownChainPath();
        }
        if (cp.dstPoolId != _dstPoolId) {
            revert UnknownChainPath();
        }
        return cp;
    }

    function unsafeGetChainPath(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId
    ) internal view returns (ChainPath storage) {
        return chainPaths[_srcPoolId][chainPathIndexLookup[abi.encodePacked(_srcPoolId, _dstChainId, _dstPoolId)]];
    }

    function getChainPathPublic(
        uint16 _srcPoolId,
        uint16 _dstChainId,
        uint16 _dstPoolId
    ) public view returns (ChainPath memory) {
        ChainPath storage cp = chainPaths[_srcPoolId][
            chainPathIndexLookup[abi.encodePacked(_srcPoolId, _dstChainId, _dstPoolId)]
        ];
        if (cp.dstChainId != _dstChainId) {
            revert UnknownChainPath();
        }
        if (cp.dstPoolId != _dstPoolId) {
            revert UnknownChainPath();
        }
        return cp;
    }

    function quoteSwap(SwapParams calldata swapParams) external view returns (uint256 amount, uint256 fee) {
        ChainPath storage cp = getChainPath(swapParams.srcPoolId, swapParams.dstChainId, swapParams.dstPoolId);
        PoolObject storage pool = poolLookup[swapParams.srcPoolId];
        if (!cp.active) revert InactiveChainPath();
        if (cp.actualKbp <= swapParams.amount) revert NotEnoughLiquidity();
        SwapMessage memory swapMessage;
        (amount, fee) = feeHandler.getFees(
            swapParams.srcPoolId,
            swapParams.amount,
            cp.actualKbp,
            cp.optimalDstBandwidth,
            cp.actualBandwidth,
            (pool.totalLiquidity * cp.weight) / pool.totalWeight
        );

        if (cp.bandwidth < swapParams.amount) revert SrcBandwidthTooLow();
        if (cp.kbp + cp.vouchers < swapMessage.amount) revert DstBandwidthTooLow();
    }

    function getPool(uint16 _poolId) external view returns (PoolObject memory) {
        return poolLookup[_poolId];
    }

    /**
     * @notice returns the effective path to move funds from A to B
     * @param _dstChainId the destination chain id
     * @param _amountToSimulate the amount to simulate to get the right path
     */
    function getEffectivePath(
        uint16 _dstChainId,
        uint256 _amountToSimulate
    ) external view returns (uint16[2] memory effectivePath) {
        unchecked {
            uint16[] memory poolsSrc = poolIdsPerChain[chainId];
            uint16[] memory poolsDst = poolIdsPerChain[_dstChainId];

            uint256 actualAmount;
            int256 highestSlipp = type(int256).min;

            uint256 poolSrcLength = poolsSrc.length;
            uint256 poolDstLength = poolsDst.length;

            // TODO: nested loops are very inefficient. will work on a better way to do this. likely yul.

            for (uint256 i; i < poolSrcLength; i++) {
                PoolObject memory poolSrc = poolLookup[poolsSrc[i]];

                for (uint256 j; j < poolDstLength; j++) {
                    PoolObject memory poolDst = poolLookup[poolsDst[j]];
                    ChainPath memory cp = getChainPathPublic(poolSrc.poolId, _dstChainId, poolDst.poolId);

                    (actualAmount, ) = feeHandler.getFees(
                        poolSrc.poolId,
                        _amountToSimulate,
                        cp.actualKbp,
                        cp.optimalDstBandwidth,
                        cp.actualBandwidth,
                        (poolSrc.totalLiquidity * cp.weight) / poolSrc.totalWeight
                    );

                    // deal with the case when optimal bandwidth or bandwidth is 0 for a chain, meaning that chain does not have liquidity
                    if (actualAmount == 0) continue;
                    int256 diff = int256(actualAmount) - int256(_amountToSimulate);

                    if (diff > highestSlipp) {
                        highestSlipp = diff;
                        effectivePath = [poolSrc.poolId, poolDst.poolId];
                    }
                }
            }
        }
    }

    /**
     * @notice Syncs chainpaths for a specific pool
     * @dev (liquidity * (weight/totalWeight)) - (kbp+vouchers)
     * @param pool the pool to sync for
     */
    function _sync(PoolObject storage pool) internal {
        uint256 undistributedVouchers = pool.undistributedVouchers;

        if (pool.totalWeight > 0) {
            uint256 cpLength = chainPaths[pool.poolId].length;
            uint256[] memory deficit = new uint256[](cpLength);
            uint256 totalDeficit = 0;

            for (uint256 i; i < cpLength; ) {
                ChainPath storage cp = chainPaths[pool.poolId][i];

                uint256 balLiq = (pool.totalLiquidity * cp.weight) / pool.totalWeight;

                uint256 currLiq = cp.kbp + cp.vouchers;
                if (balLiq > currLiq) {
                    unchecked {
                        // todo check if this overflows
                        deficit[i] = balLiq - currLiq;
                        totalDeficit = totalDeficit + deficit[i];
                    }
                }

                unchecked {
                    ++i;
                }
            }
            uint256 spentVouchers;
            if (totalDeficit == 0 && undistributedVouchers > 0) {
                for (uint256 i = 0; i < cpLength; ) {
                    ChainPath storage cp = chainPaths[pool.poolId][i];
                    uint256 consumed = (pool.undistributedVouchers * cp.weight) / pool.totalWeight;
                    unchecked {
                        spentVouchers += consumed;
                        cp.vouchers += consumed;
                        ++i;
                    }
                }
            } else if (totalDeficit <= undistributedVouchers) {
                for (uint256 i; i < cpLength; ) {
                    if (deficit[i] > 0) {
                        ChainPath storage cp = chainPaths[pool.poolId][i];
                        uint256 consumed = deficit[i];
                        unchecked {
                            // todo check if this overflows
                            spentVouchers += consumed;
                            cp.vouchers = cp.vouchers + consumed;
                        }
                    }
                    unchecked {
                        ++i;
                    }
                }
            } else {
                for (uint256 i; i < cpLength; ) {
                    if (deficit[i] > 0) {
                        ChainPath storage cp = chainPaths[pool.poolId][i];
                        uint256 proportionalDeficit = (deficit[i] * undistributedVouchers) / totalDeficit;
                        unchecked {
                            // todo check if this overflows
                            spentVouchers += proportionalDeficit;
                            cp.vouchers += proportionalDeficit;
                        }
                    }
                    unchecked {
                        ++i;
                    }
                }
            }

            pool.undistributedVouchers -= spentVouchers;
        }
    }
}

File 15 of 23 : IAssetRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

interface IAssetRouter {
    //---------------------------------------------------------------------------
    // STRUCTS
    struct ChainPath {
        bool active;
        uint16 srcPoolId;
        uint16 dstChainId;
        uint16 dstPoolId;
        uint16 weight;
        uint256 bandwidth; // local bandwidth
        uint256 actualBandwidth; // local bandwidth
        uint256 kbp; // kbp = Known Bandwidth Proof dst bandwidth
        uint256 actualKbp; // kbp = Known Bandwidth Proof dst bandwidth
        uint256 vouchers;
        uint256 optimalDstBandwidth; // optimal dst bandwidth
        address poolAddress;
    }

    struct SwapParams {
        uint16 srcPoolId;
        uint16 dstPoolId;
        uint16 dstChainId;
        uint256 amount;
        uint256 minAmount;
        address payable refundAddress;
        address to;
        bytes payload;
    }

    struct VoucherObject {
        uint256 vouchers;
        uint256 optimalDstBandwidth;
        bool swap;
    }

    struct PoolObject {
        uint16 poolId;
        address poolAddress;
        uint256 totalWeight;
        uint256 totalLiquidity;
        uint256 undistributedVouchers;
    }

    struct ChainData {
        uint16 srcPoolId;
        uint16 srcChainId;
        uint16 dstPoolId;
        uint16 dstChainId;
    }

    struct SwapMessage {
        uint16 srcChainId;
        uint16 srcPoolId;
        uint16 dstPoolId;
        address receiver;
        uint256 amount;
        uint256 fee;
        uint256 vouchers;
        uint256 optimalDstBandwidth;
        bytes32 id;
        bytes payload;
    }

    struct ReceiveSwapMessage {
        uint16 srcPoolId;
        uint16 dstPoolId;
        uint16 srcChainId;
        address receiver;
        uint256 amount;
        uint256 fee;
        uint256 vouchers;
        uint256 optimalDstBandwidth;
    }

    struct LiquidityMessage {
        uint16 srcPoolId;
        uint16 dstPoolId;
        uint256 vouchers;
        uint256 optimalDstBandwidth;
        bytes32 id;
    }

    function receiveVouchers(
        uint16 _srcChainId,
        uint16 _srcPoolId,
        uint16 _dstPoolId,
        uint256 _vouchers,
        uint256 _optimalDstBandwidth,
        bool _swap
    ) external;

    function swapRemote(
        uint16 _srcPoolId,
        uint16 _dstPoolId,
        uint16 _srcChainId,
        address _to,
        uint256 _amount,
        uint256 _fee,
        uint256 _vouchers,
        uint256 _optimalDstBandwidth
    ) external;

    enum MESSAGE_TYPE {
        NONE,
        SWAP,
        ADD_LIQUIDITY
    }

    function swap(SwapParams memory swapParams) external payable returns (bytes32);

    function getPool(uint16 _poolId) external view returns (PoolObject memory);
}

File 16 of 23 : IAssetV2.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IAssetRouter.sol";

interface IAssetV2 {
    function mint(address _to, uint256 _amountLD) external returns (uint256);

    function release(address _to, uint256 _amount) external;

    function token() external view returns (address);
}

File 17 of 23 : IBridge.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "./ILayerZeroReceiver.sol";
import "./ILayerZeroEndpoint.sol";
import "./ILayerZeroUserApplicationConfig.sol";
import "./IAssetRouter.sol";

interface IBridge is ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
    function lzReceive(
        uint16 _srcChainId,
        bytes memory _srcAddress,
        uint64 _nonce,
        bytes memory _payload
    ) external;

    // function swap(
    //     IAssetRouter.SwapParams memory _swapParams,
    //     IAssetRouter.CreditObj memory _c,
    //     IAssetRouter.SwapObj memory _s
    // ) external payable;

    // function sendVouchers(
    //     uint16 _chainId,
    //     uint16 _srcPoolId,
    //     uint16 _dstPoolId,
    //     address payable _refundAddress,
    //     IAssetRouter.VoucherObject memory _c
    // ) external payable;

    function nextNonce(uint16 dstChain_) external view returns (uint256);

    function getReceivedSwaps(uint16 _srcChainId, bytes32 _id) external view returns (IAssetRouter.SwapMessage memory);

    function getReceivedLiquidity(uint16 srcChain_, bytes32 id_)
        external
        view
        returns (IAssetRouter.LiquidityMessage memory);

    function dispatchMessage(
        uint16 _chainId,
        IAssetRouter.MESSAGE_TYPE _type,
        address payable _refundAddress,
        bytes memory _payload
    ) external payable;

    function quoteLayerZeroFee(
        uint16 _chainId,
        IAssetRouter.MESSAGE_TYPE _type,
        bytes memory _payload
    ) external view returns (uint256, uint256);
}

File 18 of 23 : IFeeCollectorV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "./IAssetV2.sol";

interface IFeeCollectorV2 {
    function collectFees(IAssetV2 asset_, uint256 amount_) external;
}

File 19 of 23 : IFeeHandler.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "./IAssetRouter.sol";

interface IFeeHandler {
    function getFees(
        uint16 _srcPoolId,
        uint256 _amount,
        uint256 _bandwidthSrc,
        uint256 _idealBandwithSrc,
        uint256 _bandwithDst,
        uint256 _idealBandwithDst
    ) external view returns (uint256, uint256);

    function getCompensatioRatio(uint256 _bandwidth, uint256 _optimalBandwidth) external pure returns (uint256);
}

File 20 of 23 : ILayerZeroEndpoint.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

import "./ILayerZeroUserApplicationConfig.sol";

interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
    // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
    // @param _dstChainId - the destination chain identifier
    // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
    // @param _payload - a custom bytes payload to send to the destination contract
    // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
    // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
    // @param _adapterParams - parameters for custom functionality. ie: pay for a specified destination gasAmount, or receive airdropped native gas from the relayer on destination
    function send(
        uint16 _dstChainId,
        bytes calldata _destination,
        bytes calldata _payload,
        address payable _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParams
    ) external payable;

    // @notice used by the messaging library to publish verified payload
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source contract (as bytes) at the source chain
    // @param _dstAddress - the address on destination chain
    // @param _nonce - the unbound message ordering nonce
    // @param _gasLimit - the gas limit for external contract execution
    // @param _payload - verified payload to send to the destination contract
    function receivePayload(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        address _dstAddress,
        uint64 _nonce,
        uint256 _gasLimit,
        bytes calldata _payload
    ) external;

    // @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);

    // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
    // @param _srcAddress - the source chain contract address
    function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);

    // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
    // @param _dstChainId - the destination chain identifier
    // @param _userApplication - the user app address on this EVM chain
    // @param _payload - the custom message to send over LayerZero
    // @param _payInZRO - if false, user app pays the protocol fee in native token
    // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
    function estimateFees(
        uint16 _dstChainId,
        address _userApplication,
        bytes calldata _payload,
        bool _payInZRO,
        bytes calldata _adapterParam
    ) external view returns (uint256 nativeFee, uint256 zroFee);

    // @notice get this Endpoint's immutable source identifier
    function getChainId() external view returns (uint16);

    // @notice the interface to retry failed message on this Endpoint destination
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    // @param _payload - the payload to be retried
    function retryPayload(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        bytes calldata _payload
    ) external;

    // @notice query if any STORED payload (message blocking) at the endpoint.
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    // @notice query if the _libraryAddress is valid for sending msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getSendLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the _libraryAddress is valid for receiving msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getReceiveLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the non-reentrancy guard for send() is on
    // @return true if the guard is on. false otherwise
    function isSendingPayload() external view returns (bool);

    // @notice query if the non-reentrancy guard for receive() is on
    // @return true if the guard is on. false otherwise
    function isReceivingPayload() external view returns (bool);

    // @notice get the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _userApplication - the contract address of the user application
    // @param _configType - type of configuration. every messaging library has its own convention.
    function getConfig(
        uint16 _version,
        uint16 _chainId,
        address _userApplication,
        uint256 _configType
    ) external view returns (bytes memory);

    // @notice get the send() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getSendVersion(address _userApplication) external view returns (uint16);

    // @notice get the lzReceive() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getReceiveVersion(address _userApplication) external view returns (uint16);
}

File 21 of 23 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroReceiver {
    // @notice LayerZero endpoint will invoke this function to deliver the message on the destination
    // @param _srcChainId - the source endpoint identifier
    // @param _srcAddress - the source sending contract address from the source chain
    // @param _nonce - the ordered message nonce
    // @param _payload - the signed payload is the UA bytes has encoded to be sent
    function lzReceive(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        bytes calldata _payload
    ) external;
}

File 22 of 23 : ILayerZeroUserApplicationConfig.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroUserApplicationConfig {
    // @notice set the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _configType - type of configuration. every messaging library has its own convention.
    // @param _config - configuration in the bytes. can encode arbitrary content.
    function setConfig(
        uint16 _version,
        uint16 _chainId,
        uint256 _configType,
        bytes calldata _config
    ) external;

    // @notice set the send() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setSendVersion(uint16 _version) external;

    // @notice set the lzReceive() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setReceiveVersion(uint16 _version) external;

    // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
    // @param _srcChainId - the chainId of the source chain
    // @param _srcAddress - the contract address of the source contract at the source chain
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

File 23 of 23 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >= 0.4.22 <0.9.0;

library console {
	address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

	function _sendLogPayload(bytes memory payload) private view {
		uint256 payloadLength = payload.length;
		address consoleAddress = CONSOLE_ADDRESS;
		assembly {
			let payloadStart := add(payload, 32)
			let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
		}
	}

	function log() internal view {
		_sendLogPayload(abi.encodeWithSignature("log()"));
	}

	function logInt(int256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
	}

	function logUint(uint256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
	}

	function logString(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function logBool(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function logAddress(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function logBytes(bytes memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
	}

	function logBytes1(bytes1 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
	}

	function logBytes2(bytes2 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
	}

	function logBytes3(bytes3 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
	}

	function logBytes4(bytes4 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
	}

	function logBytes5(bytes5 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
	}

	function logBytes6(bytes6 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
	}

	function logBytes7(bytes7 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
	}

	function logBytes8(bytes8 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
	}

	function logBytes9(bytes9 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
	}

	function logBytes10(bytes10 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
	}

	function logBytes11(bytes11 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
	}

	function logBytes12(bytes12 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
	}

	function logBytes13(bytes13 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
	}

	function logBytes14(bytes14 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
	}

	function logBytes15(bytes15 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
	}

	function logBytes16(bytes16 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
	}

	function logBytes17(bytes17 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
	}

	function logBytes18(bytes18 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
	}

	function logBytes19(bytes19 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
	}

	function logBytes20(bytes20 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
	}

	function logBytes21(bytes21 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
	}

	function logBytes22(bytes22 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
	}

	function logBytes23(bytes23 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
	}

	function logBytes24(bytes24 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
	}

	function logBytes25(bytes25 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
	}

	function logBytes26(bytes26 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
	}

	function logBytes27(bytes27 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
	}

	function logBytes28(bytes28 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
	}

	function logBytes29(bytes29 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
	}

	function logBytes30(bytes30 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
	}

	function logBytes31(bytes31 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
	}

	function logBytes32(bytes32 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
	}

	function log(uint256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
	}

	function log(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function log(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function log(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function log(uint256 p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
	}

	function log(uint256 p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
	}

	function log(uint256 p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
	}

	function log(uint256 p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
	}

	function log(string memory p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
	}

	function log(string memory p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
	}

	function log(string memory p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
	}

	function log(string memory p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
	}

	function log(bool p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
	}

	function log(bool p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
	}

	function log(bool p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
	}

	function log(bool p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
	}

	function log(address p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
	}

	function log(address p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
	}

	function log(address p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
	}

	function log(address p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
	}

	function log(uint256 p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
	}

	function log(string memory p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
	}

	function log(string memory p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
	}

	function log(string memory p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
	}

	function log(string memory p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
	}

	function log(bool p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
	}

	function log(bool p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
	}

	function log(bool p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
	}

	function log(bool p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
	}

	function log(bool p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
	}

	function log(bool p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
	}

	function log(bool p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
	}

	function log(bool p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
	}

	function log(address p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
	}

	function log(address p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
	}

	function log(address p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
	}

	function log(address p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
	}

	function log(address p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
	}

	function log(address p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
	}

	function log(address p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
	}

	function log(address p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
	}

	function log(address p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
	}

	function log(address p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
	}

	function log(address p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
	}

	function log(address p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
	}

}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"contract IFeeHandler","name":"_feeHandler","type":"address"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"contract IFeeCollectorV2","name":"_feeCollector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ActiveChainPath","type":"error"},{"inputs":[],"name":"ChainPathExists","type":"error"},{"inputs":[],"name":"DstBandwidthTooLow","type":"error"},{"inputs":[],"name":"FeeLibraryZero","type":"error"},{"inputs":[],"name":"InactiveChainPath","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"NotEnoughLiquidity","type":"error"},{"inputs":[],"name":"SlippageTooHigh","type":"error"},{"inputs":[],"name":"SrcBandwidthTooLow","type":"error"},{"inputs":[],"name":"SyncDeviationTooHigh","type":"error"},{"inputs":[],"name":"UnknownChainPath","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"weight","type":"uint256"}],"name":"ChainPathUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"vouchers","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"}],"name":"CrossChainLiquidityInitiated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"internalType":"uint256","name":"vouchers","type":"uint256"},{"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"},{"internalType":"bytes32","name":"id","type":"bytes32"}],"indexed":false,"internalType":"struct IAssetRouter.LiquidityMessage","name":"_message","type":"tuple"}],"name":"CrossChainLiquidityPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vouchers","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"}],"name":"CrossChainSwapInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"srcChainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"CrossChainSwapPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeeHandler","type":"address"},{"indexed":false,"internalType":"address","name":"newFeeHandler","type":"address"}],"name":"FeeHandlerUpdated","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":false,"internalType":"uint16","name":"dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"vouchers","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"}],"name":"SendVouchers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SwapRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDeviation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDeviation","type":"uint256"}],"name":"SyncDeviationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"}],"name":"VouchersReceived","type":"event"},{"inputs":[],"name":"BP_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BRIDGE_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":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"}],"name":"activateChainPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridge","outputs":[{"internalType":"contract IBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"chainPathIndexLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"chainPaths","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"internalType":"uint16","name":"weight","type":"uint16"},{"internalType":"uint256","name":"bandwidth","type":"uint256"},{"internalType":"uint256","name":"actualBandwidth","type":"uint256"},{"internalType":"uint256","name":"kbp","type":"uint256"},{"internalType":"uint256","name":"actualKbp","type":"uint256"},{"internalType":"uint256","name":"vouchers","type":"uint256"},{"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"},{"internalType":"address","name":"poolAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"},{"internalType":"uint16","name":"_weight","type":"uint16"},{"internalType":"address","name":"_poolAddress","type":"address"}],"name":"createChainPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint16","name":"_poolId","type":"uint16"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"contract IFeeCollectorV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeHandler","outputs":[{"internalType":"contract IFeeHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"}],"name":"getChainPathPublic","outputs":[{"components":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"internalType":"uint16","name":"weight","type":"uint16"},{"internalType":"uint256","name":"bandwidth","type":"uint256"},{"internalType":"uint256","name":"actualBandwidth","type":"uint256"},{"internalType":"uint256","name":"kbp","type":"uint256"},{"internalType":"uint256","name":"actualKbp","type":"uint256"},{"internalType":"uint256","name":"vouchers","type":"uint256"},{"internalType":"uint256","name":"optimalDstBandwidth","type":"uint256"},{"internalType":"address","name":"poolAddress","type":"address"}],"internalType":"struct IAssetRouter.ChainPath","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_poolId","type":"uint16"}],"name":"getChainPathsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_amountToSimulate","type":"uint256"}],"name":"getEffectivePath","outputs":[{"internalType":"uint16[2]","name":"effectivePath","type":"uint16[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_poolId","type":"uint16"}],"name":"getPool","outputs":[{"components":[{"internalType":"uint16","name":"poolId","type":"uint16"},{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"uint256","name":"undistributedVouchers","type":"uint256"}],"internalType":"struct IAssetRouter.PoolObject","name":"","type":"tuple"}],"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":"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":"uint16","name":"","type":"uint16"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdsPerChain","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"poolLookup","outputs":[{"internalType":"uint16","name":"poolId","type":"uint16"},{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"uint256","name":"undistributedVouchers","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct IAssetRouter.SwapParams","name":"swapParams","type":"tuple"}],"name":"quoteSwap","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"},{"internalType":"uint256","name":"_vouchers","type":"uint256"},{"internalType":"uint256","name":"_optimalDstBandwidth","type":"uint256"},{"internalType":"bool","name":"_swap","type":"bool"}],"name":"receiveVouchers","outputs":[],"stateMutability":"nonpayable","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":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"},{"internalType":"address payable","name":"_refundAddress","type":"address"}],"name":"sendVouchers","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IBridge","name":"_newBridge","type":"address"}],"name":"setBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeHandler","type":"address"}],"name":"setFeeLibrary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_syncDeviation","type":"uint256"}],"name":"setSyncDeviation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"},{"internalType":"uint16","name":"_weight","type":"uint16"}],"name":"setWeightForChainPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"srcPoolId","type":"uint16"},{"internalType":"uint16","name":"dstPoolId","type":"uint16"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct IAssetRouter.SwapParams","name":"swapParams","type":"tuple"}],"name":"swap","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint16","name":"_dstPoolId","type":"uint16"},{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_vouchers","type":"uint256"},{"internalType":"uint256","name":"_optimalDstBandwidth","type":"uint256"}],"name":"swapRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_poolId","type":"uint16"}],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"syncDeviation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b50604051620041b0380380620041b0833981016040819052620000349162000184565b6001805562000045600033620000bb565b620000717f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f33620000bb565b6005805461ffff90931661ffff1990931692909217909155600780546001600160a01b039384166001600160a01b03199182161790915560088054929093169116179055620001de565b620000c78282620000cb565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620000c7576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001273390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6001600160a01b03811681146200018157600080fd5b50565b6000806000606084860312156200019a57600080fd5b8351620001a7816200016b565b602085015190935061ffff81168114620001c057600080fd5b6040850151909250620001d3816200016b565b809150509250925092565b613fc280620001ee6000396000f3fe6080604052600436106102345760003560e01c80637be661bc11610138578063abe685cd116100b0578063c415b95c1161007f578063dd0aef8711610064578063dd0aef8714610816578063e239564b14610836578063e78cea921461085657600080fd5b8063c415b95c146107d6578063d547741f146107f657600080fd5b8063abe685cd1461072e578063b5bfddea14610744578063b7dcdaaa14610778578063c2279cc3146107a957600080fd5b806391df699f116101075780639a8a0592116100ec5780639a8a0592146106e8578063a217fddf14610703578063a86171251461071857600080fd5b806391df699f146106a0578063947b6fdd146106b357600080fd5b80637be661bc146105fc5780638dd148021461061c578063904217c31461063c57806391d148541461065c57600080fd5b806336a141d3116101cb5780635c73da181161019a578063752172cc1161017f578063752172cc146105315780637693402b146105bc5780637b779130146105dc57600080fd5b80635c73da18146104fe578063701a486c1461051e57600080fd5b806336a141d3146104465780633c93adee146104795780634b5cacbc146104b15780635becbd9b146104d157600080fd5b80632ce12669116102075780632ce12669146103755780632f2ff15d146103e45780633380b9831461040657806336568abe1461042657600080fd5b806301ffc9a714610239578063073a559b1461026e5780631f391d7c146102b4578063248a9ca314610345575b600080fd5b34801561024557600080fd5b5061025961025436600461359b565b610876565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a66102893660046135db565b805160208183018101805160038252928201919093012091525481565b604051908152602001610265565b3480156102c057600080fd5b506102d46102cf36600461369e565b6108ad565b604080519c15158d5261ffff9b8c1660208e0152998b16998c019990995296891660608b015297909416608089015260a088019290925260c087015260e08601526101008501526101208401929092526101408301919091526001600160a01b031661016082015261018001610265565b34801561035157600080fd5b506102a66103603660046136c8565b60009081526020819052604090206001015490565b34801561038157600080fd5b506103956103903660046136e1565b610943565b6040516102659190600060a08201905061ffff83511682526001600160a01b03602084015116602083015260408301516040830152606083015160608301526080830151608083015292915050565b3480156103f057600080fd5b506104046103ff366004613711565b6109e3565b005b34801561041257600080fd5b506104046104213660046136c8565b610a0d565b34801561043257600080fd5b50610404610441366004613711565b610a7d565b34801561045257600080fd5b5061046661046136600461369e565b610b0e565b60405161ffff9091168152602001610265565b34801561048557600080fd5b50600754610499906001600160a01b031681565b6040516001600160a01b039091168152602001610265565b3480156104bd57600080fd5b506104046104cc366004613741565b610b55565b3480156104dd57600080fd5b506104f16104ec36600461369e565b610bfe565b604051610265919061375e565b34801561050a57600080fd5b50610404610519366004613793565b610fd2565b6102a661052c3660046137e7565b61109c565b34801561053d57600080fd5b5061058761054c3660046136e1565b600460205260009081526040902080546001820154600283015460039093015461ffff831693620100009093046001600160a01b0316929085565b6040805161ffff90961686526001600160a01b039094166020860152928401919091526060830152608082015260a001610265565b3480156105c857600080fd5b506104046105d73660046136e1565b611290565b3480156105e857600080fd5b506104046105f736600461383d565b6112af565b34801561060857600080fd5b50610404610617366004613880565b6114b7565b34801561062857600080fd5b50610404610637366004613741565b61161a565b34801561064857600080fd5b506104046106573660046138cc565b611655565b34801561066857600080fd5b50610259610677366004613711565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6102a66106ae366004613936565b611742565b3480156106bf57600080fd5b506106d36106ce366004613936565b611dc9565b60408051928352602083019190915201610265565b3480156106f457600080fd5b506005546104669061ffff1681565b34801561070f57600080fd5b506102a6600081565b34801561072457600080fd5b506102a6600a5481565b34801561073a57600080fd5b506102a661271081565b34801561075057600080fd5b506102a67f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f81565b34801561078457600080fd5b506102a66107933660046136e1565b61ffff1660009081526002602052604090205490565b3480156107b557600080fd5b506107c96107c436600461383d565b612036565b6040516102659190613972565b3480156107e257600080fd5b50600854610499906001600160a01b031681565b34801561080257600080fd5b50610404610811366004613711565b61223b565b34801561082257600080fd5b50610404610831366004613a2f565b612260565b34801561084257600080fd5b50610404610851366004613a98565b612759565b34801561086257600080fd5b50600954610499906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b14806108a757506301ffc9a760e01b6001600160e01b03198316145b92915050565b600260205281600052604060002081815481106108c957600080fd5b60009182526020909120600890910201805460018201546002830154600384015460048501546005860154600687015460079097015460ff8716995061ffff61010088048116995063010000008804811698650100000000008904821698600160381b90049091169695949392916001600160a01b03168c565b6109826040518060a00160405280600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b5061ffff908116600090815260046020908152604091829020825160a08101845281549485168152620100009094046001600160a01b0316918401919091526001810154918301919091526002810154606083015260030154608082015290565b6000828152602081905260409020600101546109fe816129bf565b610a0883836129c9565b505050565b6000610a18816129bf565b612710821115610a3b5760405163e7412eeb60e01b815260040160405180910390fd5b600a5460408051918252602082018490527f4f1157e19438bfda32a61ecb89140237e8f062bb9353c62532808b15c860e5a8910160405180910390a150600a55565b6001600160a01b0381163314610b005760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610b0a8282612a67565b5050565b60066020528160005260406000208181548110610b2a57600080fd5b9060005260206000209060109182820401919006600202915091509054906101000a900461ffff1681565b6000610b60816129bf565b6001600160a01b038216610b875760405163133e7b6160e21b815260040160405180910390fd5b600754604080516001600160a01b03928316815291841660208301527f98f22970df215e57c23c0c6140481936298fab08d4b0f0e351cae582921c90a2910160405180910390a1506007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b610c0661357d565b60055461ffff16600090815260066020908152604080832080548251818502810185019093528083529192909190830182828015610c8b57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610c525790505b5050505061ffff861660009081526006602090815260408083208054825181850281018501909352808352959650929490935090830182828015610d1657602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610cdd5790505b505085518451949550600094600160ff1b94509092509050835b82811015610fc557600060046000898481518110610d5057610d50613b12565b60209081029190910181015161ffff90811683528282019390935260409182016000908120835160a08101855281549586168152620100009095046001600160a01b031692850192909252600182015492840192909252600281015460608401526003015460808301529091505b83811015610fbb576000600460008a8481518110610dde57610dde613b12565b602002602001015161ffff1661ffff1681526020019081526020016000206040518060a00160405290816000820160009054906101000a900461ffff1661ffff1661ffff1681526020016000820160029054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600182015481526020016002820154815260200160038201548152505090506000610e8b84600001518f8460000151612036565b9050600760009054906101000a90046001600160a01b03166001600160a01b0316632f8dad4b85600001518f8461010001518561014001518660c001518a60400151886080015161ffff168c606001510281610ee957610ee9613b28565b6040516001600160e01b031960e08a901b16815261ffff90971660048801526024870195909552604486019390935260648501919091526084840152900460a482015260c4016040805180830381865afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613b3e565b5098506000899003610f82575050610fb3565b8c890388811315610faf5760408051808201909152855161ffff908116825284511660208201529c509750875b5050505b600101610dbe565b5050600101610d30565b5050505050505092915050565b6000610fdd816129bf565b6000610fea868686612ae6565b61ffff80881660009081526004602052604090208254600182015493945090928683169261102092600160381b90041690613b78565b61102a9190613b8b565b6001820155815468ffff000000000000001916600160381b61ffff86811691820292909217845560408051898416815292881660208401528201527fcd60dbaa3a0d4b6605e8b3501b72feeeaa1716f70e29bd28a463911b1070547a906060015b60405180910390a150505050505050565b60006110a6612bdf565b60006110b3868686612ae6565b61ffff87166000908152600460205260408120919250806110d5848483612c38565b60095460405163068d8d7d60e21b815261ffff8c1660048201529294509092506001600160a01b0316908190631a3635f490602401602060405180830381865afa158015611127573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114b9190613b9e565b4260026040516020016111619493929190613bdc565b604051602081830303815290604052805190602001209450600960009054906101000a90046001600160a01b03166001600160a01b03166396806f7a348a60028a60028f8e8a8a8f6040516020016111be96959493929190613c15565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016111ec9493929190613caa565b6000604051808303818588803b15801561120557600080fd5b505af1158015611219573d6000803e3d6000fd5b50506040805189815261ffff8e811660208301528d8116828401528c1660608201526080810187905260a0810186905290513394507f50cc914822484a1d459548821999078bf15c508132451f53f92b67132da1139093509081900360c0019150a25050505061128860018055565b949350505050565b61ffff811660009081526004602052604090206112ac90612cca565b50565b60006112ba816129bf565b60006112c7858585612ae6565b805490915060ff16156112ed57604051632a8617b560e21b815260040160405180910390fd5b805460ff1916600117815560055461ffff908116600090815260066020526040808220549287168252812054909190825b828110156113915760055461ffff90811660009081526006602052604090208054918b16918390811061135357611353613b12565b60009182526020909120601082040154600f9091166002026101000a900461ffff160361137f57600193505b8061138981613d04565b91505061131e565b50826113e55760055461ffff9081166000908152600660209081526040822080546001810182559083529120601082040180548b84166002600f909416939093026101000a92830292909302199092161790555b6000925060005b8181101561145c5761ffff88811660009081526006602052604090208054918916918390811061141e5761141e613b12565b60009182526020909120601082040154600f9091166002026101000a900461ffff160361144a57600193505b8061145481613d04565b9150506113ec565b50826114ad5761ffff8088166000908152600660209081526040822080546001810182559083529120601082040180548984166002600f909416939093026101000a92830292909302199092161790555b5050505050505050565b61ffff82166000908152600460205260408120600281018054919284926114df908490613b8b565b92505081905550818160030160008282546114fa9190613b8b565b90915550611509905081612cca565b805460408051637e062a3560e11b81529051611596923392620100009091046001600160a01b0316918691839163fc0c546a916004808201926020929091908290030181865afa158015611561573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115859190613d1d565b6001600160a01b031692919061302f565b80546040516340c10f1960e01b81526001600160a01b0386811660048301526024820185905262010000909204909116906340c10f19906044016020604051808303816000875af11580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190613b9e565b5050505050565b6000611625816129bf565b506009805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b61165d612bdf565b7f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f611687816129bf565b6000611694868989612ae6565b9050848160010160008282546116aa9190613b8b565b909155508390506116cf57848160020160008282546116c99190613b8b565b90915550505b838160060154146116e257600681018490555b6040805161ffff808b16825289166020820152908101869052606081018590527f39c95231d9c33e157609ecd9c4deb49ed4a98afcf489adde59f847a0936c14eb9060800160405180910390a1505061173a60018055565b505050505050565b600061174c612bdf565b600061178361175e60208501856136e1565b61176e60608601604087016136e1565b61177e60408701602088016136e1565b612ae6565b9050600060048161179760208701876136e1565b61ffff1681526020810191909152604001600020825490915060ff166117d05760405163303868b960e21b815260040160405180910390fd5b83606001358260040154116117f85760405163bb55fd2760e01b815260040160405180910390fd5b611866604051806101400160405280600061ffff168152602001600061ffff168152602001600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008019168152602001606081525090565b61187360e0860186613d3a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101208201526007546001600160a01b0316632f8dad4b6118cb60208801886136e1565b876060013586600401548760060154886002015488600101548a60000160079054906101000a900461ffff1661ffff168a6002015461190a9190613d88565b6119149190613d9f565b6040516001600160e01b031960e089901b16815261ffff9096166004870152602486019490945260448501929092526064840152608483015260a482015260c4016040805180830381865afa158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190613b3e565b60a08301526080808301829052860135106119c35760405163428637bb60e11b815260040160405180910390fd5b84606001358360010154116119eb57604051635a39b5af60e11b815260040160405180910390fd5b806080015183600501548460030154611a049190613b8b565b11611a2257604051631dab39a560e31b815260040160405180910390fd5b8060800151836001015411611a4a57604051631dab39a560e31b815260040160405180910390fd5b8060800151836001016000828254611a629190613b78565b90915550506080810151600284018054600090611a80908490613b78565b90915550506080810151600484018054600090611a9e908490613b8b565b925050819055508460600135826003016000828254611abd9190613b8b565b9091555050600a54600283015461271091611ad791613d88565b611ae19190613d9f565b826003015410611af457611af482612cca565b611b0083836001612c38565b60e083015260c0820152815460408051637e062a3560e11b81529051611b66923392620100009091046001600160a01b03169160608a013591839163fc0c546a916004808201926020929091908290030181865afa158015611561573d6000803e3d6000fd5b6009546001600160a01b031680631a3635f4611b886060890160408a016136e1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613b9e565b426001604051602001611c019493929190613bdc565b60408051601f1981840301815291815281516020909201919091206101008301526009546001600160a01b0316906396806f7a903490611c479060608a01908a016136e1565b6001611c5960c08b0160a08c01613741565b6001611c6860208d018d6136e1565b611c7860408e0160208f016136e1565b8d60c0016020810190611c8b9190613741565b8a608001518b60a001518c60c001518d60e001518e61010001518f6101200151604051602001611cc49a99989796959493929190613dc1565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611cf29493929190613caa565b6000604051808303818588803b158015611d0b57600080fd5b505af1158015611d1f573d6000803e3d6000fd5b5050506101008301513392507f26fae55a6e1666b8a220d47d475eb9b0e2572a730d4202cb2e0a738a50e910e09150611d5b60208901896136e1565b611d6b60608a0160408b016136e1565b611d7b60408b0160208c016136e1565b8a606001358760a001518860c001518960e001518a6101200151604051611daa99989796959493929190613e49565b60405180910390a2610100015192505050611dc460018055565b919050565b60008080611dfd611ddd60208601866136e1565b611ded60608701604088016136e1565b61177e60408801602089016136e1565b90506000600481611e1160208801886136e1565b61ffff1681526020810191909152604001600020825490915060ff16611e4a5760405163303868b960e21b815260040160405180910390fd5b8460600135826004015411611e7257604051634323a55560e01b815260040160405180910390fd5b611ee0604051806101400160405280600061ffff168152602001600061ffff168152602001600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008019168152602001606081525090565b6007546001600160a01b0316632f8dad4b611efe60208901896136e1565b886060013586600401548760060154886002015488600101548a60000160079054906101000a900461ffff1661ffff168a60020154611f3d9190613d88565b611f479190613d9f565b6040516001600160e01b031960e089901b16815261ffff9096166004870152602486019490945260448501929092526064840152608483015260a482015260c4016040805180830381865afa158015611fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc89190613b3e565b6001850154919650945060608701351115611ff657604051635a39b5af60e11b815260040160405180910390fd5b80608001518360050154846003015461200f9190613b8b565b101561202e57604051631dab39a560e31b815260040160405180910390fd5b505050915091565b604080516101808101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261ffff8716825260028152838220935160f088811b6001600160f01b03199081169383019390935287811b8316602283015286901b90911660248201529192909160039060260160408051601f19818403018152908290526120f891613ea8565b9081526020016040518091039020548154811061211757612117613b12565b60009182526020909120600890910201805490915061ffff858116630100000090920416146121595760405163069cd95760e41b815260040160405180910390fd5b805461ffff84811665010000000000909204161461218a5760405163069cd95760e41b815260040160405180910390fd5b6040805161018081018252825460ff81161515825261ffff610100808304821660208501526301000000830482169484019490945265010000000000820481166060840152600160381b909104166080820152600183015460a0820152600283015460c0820152600383015460e0820152600483015491810191909152600582015461012082015260068201546101408201526007909101546001600160a01b031661016082015290509392505050565b600082815260208190526040902060010154612256816129bf565b610a088383612a67565b600061226b816129bf565b61ffff8616600090815260026020526040812054905b818110156123cf5761ffff881660009081526002602052604081208054839081106122ae576122ae613b12565b600091825260208083206040805161018081018252600894909402909101805460ff81161515855261010080820461ffff9081169587019590955263010000008204851693860184905265010000000000820485166060870152600160381b90910484166080860152600182015460a0860152600282015460c0860152600382015460e086015260048201549085015260058101546101208501526006810154610140850152600701546001600160a01b03166101608401529193508a1614801561238457508761ffff16826060015161ffff16145b801561239b57508961ffff16826020015161ffff16145b905080156123bc57604051632a8617b560e21b815260040160405180910390fd5b5050806123c890613d04565b9050612281565b5061ffff87166000908152600460205260409020546201000090046001600160a01b0316612491576040805160a08101825261ffff808a168083526001600160a01b03808816602080860191825260008688018181526060880182815260808901838152968352600490935297902095518654925190931662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090921692909416919091171783559251600183015551600282015590516003909101555b61ffff87811660009081526004602052604081206001018054928716929091906124bc908490613b8b565b909155505061ffff87166000908152600260209081526040918290205491516001600160f01b031960f08b811b82169383019390935289831b811660228301529188901b909116602482015260039060260160408051601f198184030181529082905261252891613ea8565b908152602001604051809103902081905550600260008861ffff1661ffff1681526020019081526020016000206040518061018001604052806000151581526020018961ffff1681526020018861ffff1681526020018761ffff1681526020018661ffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001856001600160a01b0316815250908060018154018082558091505060019003906000526020600020906008020160009091909190915060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548161ffff021916908361ffff16021790555060608201518160000160056101000a81548161ffff021916908361ffff16021790555060808201518160000160076101000a81548161ffff021916908361ffff16021790555060a0820151816001015560c0820151816002015560e082015181600301556101008201518160040155610120820151816005015561014082015181600601556101608201518160070160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555050507fcd60dbaa3a0d4b6605e8b3501b72feeeaa1716f70e29bd28a463911b1070547a86868660405161108b9392919061ffff93841681529183166020830152909116604082015260600190565b612761612bdf565b7f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f61278b816129bf565b600061279889898c6130a4565b61ffff8a16600090815260046020526040812060018301805493945090928792906127c4908490613b8b565b9091555050600682015484146127dc57600682018490555b6040805161ffff808c1682528d166020820152908101869052606081018590527f39c95231d9c33e157609ecd9c4deb49ed4a98afcf489adde59f847a0936c14eb9060800160405180910390a18682600301600082825461283d9190613b78565b92505081905550868260040160008282546128589190613b78565b92505081905550868260020160008282546128739190613b8b565b90915550508054604051630357371d60e01b81526001600160a01b038a81166004830152602482018a90526201000090920490911690630357371d90604401600060405180830381600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050506000861180156128fe57506008546001600160a01b031615155b15612950576040518681527fc472cb3a7a659a876494d66b3063145f279701771d6150b9329c31611ed6405c9060200160405180910390a18581600201600082825461294a9190613b8b565b90915550505b6040805161ffff8d811682528c811660208301528b16818301526001600160a01b038a1660608201526080810189905260a0810188905290517fcffd018da5de203cecdd9ba279e59cc5dc6ed918472a4a012beb369c7e09fe349181900360c00190a15050506114ad60018055565b6112ac8133613140565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610b0a576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612a233390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610b0a576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61ffff8316600090815260026020908152604080832090516001600160f01b031960f088811b82169483019490945286841b811660228301529285901b9092166024830152829160039060260160408051601f1981840301815290829052612b4d91613ea8565b90815260200160405180910390205481548110612b6c57612b6c613b12565b60009182526020909120600890910201805490915061ffff85811663010000009092041614612bae5760405163069cd95760e41b815260040160405180910390fd5b805461ffff8481166501000000000090920416146112885760405163069cd95760e41b815260040160405180910390fd5b600260015403612c315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610af7565b6002600155565b8254600090819060ff16612c5f5760405163303868b960e21b815260040160405180910390fd5b6005850154600386018054909101905582612c8557600585015460048601805490910190555b60058501805460009091556001850154865460028701549294509091612cb691600160381b900461ffff1690613d88565b612cc09190613d9f565b9050935093915050565b6003810154600182015415610b0a57815461ffff16600090815260026020526040812054908167ffffffffffffffff811115612d0857612d086135c5565b604051908082528060200260200182016040528015612d31578160200160208202803683370190505b5090506000805b83811015612e1557855461ffff166000908152600260205260408120805483908110612d6657612d66613b12565b60009182526020822060018a015460089290920201805460028b0154919450612d9b91600160381b90910461ffff1690613d88565b612da59190613d9f565b9050600082600501548360030154612dbd9190613b8b565b905080821115612e0757808203868581518110612ddc57612ddc613b12565b602002602001018181525050858481518110612dfa57612dfa613b12565b6020026020010151850194505b836001019350505050612d38565b50600081158015612e265750600085115b15612eba5760005b84811015612eb457865461ffff166000908152600260205260408120805483908110612e5c57612e5c613b12565b60009182526020822060018b015460089290920201805460038c0154919450612e9191600160381b90910461ffff1690613d88565b612e9b9190613d9f565b6005909201805483019055509190910190600101612e2e565b5061300e565b848211612f5d5760005b84811015612eb4576000848281518110612ee057612ee0613b12565b60200260200101511115612f5557865461ffff166000908152600260205260408120805483908110612f1457612f14613b12565b906000526020600020906008020190506000858381518110612f3857612f38613b12565b602090810291909101015160059092018054830190555091909101905b600101612ec4565b60005b8481101561300c576000848281518110612f7c57612f7c613b12565b6020026020010151111561300457865461ffff166000908152600260205260408120805483908110612fb057612fb0613b12565b9060005260206000209060080201905060008488878581518110612fd657612fd6613b12565b6020026020010151612fe89190613d88565b612ff29190613d9f565b60059092018054830190555091909101905b600101612f60565b505b808660030160008282546130229190613b78565b9091555050505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905261309e9085906131b3565b50505050565b61ffff8316600090815260026020908152604080832090516001600160f01b031960f088811b82169483019490945286841b811660228301529285901b90921660248301529060039060260160408051601f198184030181529082905261310a91613ea8565b9081526020016040518091039020548154811061312957613129613b12565b906000526020600020906008020190509392505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610b0a5761317181613298565b61317c8360206132aa565b60405160200161318d929190613ec4565b60408051601f198184030181529082905262461bcd60e51b8252610af791600401613f45565b6000613208826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661345a9092919063ffffffff16565b805190915015610a0857808060200190518101906132269190613f58565b610a085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610af7565b60606108a76001600160a01b03831660145b606060006132b9836002613d88565b6132c4906002613b8b565b67ffffffffffffffff8111156132dc576132dc6135c5565b6040519080825280601f01601f191660200182016040528015613306576020820181803683370190505b509050600360fc1b8160008151811061332157613321613b12565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061335057613350613b12565b60200101906001600160f81b031916908160001a9053506000613374846002613d88565b61337f906001613b8b565b90505b6001811115613404577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106133c0576133c0613b12565b1a60f81b8282815181106133d6576133d6613b12565b60200101906001600160f81b031916908160001a90535060049490941c936133fd81613f75565b9050613382565b5083156134535760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610af7565b9392505050565b6060611288848460008585600080866001600160a01b031685876040516134819190613ea8565b60006040518083038185875af1925050503d80600081146134be576040519150601f19603f3d011682016040523d82523d6000602084013e6134c3565b606091505b50915091506134d4878383876134df565b979650505050505050565b6060831561354e578251600003613547576001600160a01b0385163b6135475760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610af7565b5081611288565b61128883838151156135635781518083602001fd5b8060405162461bcd60e51b8152600401610af79190613f45565b60405180604001604052806002906020820280368337509192915050565b6000602082840312156135ad57600080fd5b81356001600160e01b03198116811461345357600080fd5b634e487b7160e01b600052604160045260246000fd5b6000602082840312156135ed57600080fd5b813567ffffffffffffffff8082111561360557600080fd5b818401915084601f83011261361957600080fd5b81358181111561362b5761362b6135c5565b604051601f8201601f19908116603f01168101908382118183101715613653576136536135c5565b8160405282815287602084870101111561366c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b803561ffff81168114611dc457600080fd5b600080604083850312156136b157600080fd5b6136ba8361368c565b946020939093013593505050565b6000602082840312156136da57600080fd5b5035919050565b6000602082840312156136f357600080fd5b6134538261368c565b6001600160a01b03811681146112ac57600080fd5b6000806040838503121561372457600080fd5b823591506020830135613736816136fc565b809150509250929050565b60006020828403121561375357600080fd5b8135613453816136fc565b60408101818360005b600281101561378a57815161ffff16835260209283019290910190600101613767565b50505092915050565b600080600080608085870312156137a957600080fd5b6137b28561368c565b93506137c06020860161368c565b92506137ce6040860161368c565b91506137dc6060860161368c565b905092959194509250565b600080600080608085870312156137fd57600080fd5b6138068561368c565b93506138146020860161368c565b92506138226040860161368c565b91506060850135613832816136fc565b939692955090935050565b60008060006060848603121561385257600080fd5b61385b8461368c565b92506138696020850161368c565b91506138776040850161368c565b90509250925092565b60008060006060848603121561389557600080fd5b83356138a0816136fc565b92506138ae6020850161368c565b9150604084013590509250925092565b80151581146112ac57600080fd5b60008060008060008060c087890312156138e557600080fd5b6138ee8761368c565b95506138fc6020880161368c565b945061390a6040880161368c565b9350606087013592506080870135915060a0870135613928816138be565b809150509295509295509295565b60006020828403121561394857600080fd5b813567ffffffffffffffff81111561395f57600080fd5b8201610100818503121561345357600080fd5b81511515815261018081016020830151613992602084018261ffff169052565b5060408301516139a8604084018261ffff169052565b5060608301516139be606084018261ffff169052565b5060808301516139d4608084018261ffff169052565b5060a0838101519083015260c0808401519083015260e08084015190830152610100808401519083015261012080840151908301526101408084015190830152610160928301516001600160a01b0316929091019190915290565b600080600080600060a08688031215613a4757600080fd5b613a508661368c565b9450613a5e6020870161368c565b9350613a6c6040870161368c565b9250613a7a6060870161368c565b91506080860135613a8a816136fc565b809150509295509295909350565b600080600080600080600080610100898b031215613ab557600080fd5b613abe8961368c565b9750613acc60208a0161368c565b9650613ada60408a0161368c565b95506060890135613aea816136fc565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008060408385031215613b5157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b818103818111156108a7576108a7613b62565b808201808211156108a7576108a7613b62565b600060208284031215613bb057600080fd5b5051919050565b60038110613bd557634e487b7160e01b600052602160045260246000fd5b60f81b9052565b6bffffffffffffffffffffffff198560601b168152836014820152826034820152613c0a6054820183613bb7565b605501949350505050565b613c1f8188613bb7565b6001600160f01b031960f096871b811660018301529490951b9093166003850152600584019190915260258301526045820152606501919050565b60005b83811015613c75578181015183820152602001613c5d565b50506000910152565b60008151808452613c96816020860160208601613c5a565b601f01601f19169290920160200192915050565b61ffff85168152600060038510613cd157634e487b7160e01b600052602160045260246000fd5b8460208301526001600160a01b038416604083015260806060830152613cfa6080830184613c7e565b9695505050505050565b600060018201613d1657613d16613b62565b5060010190565b600060208284031215613d2f57600080fd5b8151613453816136fc565b6000808335601e19843603018112613d5157600080fd5b83018035915067ffffffffffffffff821115613d6c57600080fd5b602001915036819003821315613d8157600080fd5b9250929050565b80820281158282048414176108a7576108a7613b62565b600082613dbc57634e487b7160e01b600052601260045260246000fd5b500490565b613dcb818c613bb7565b600061ffff60f01b808c60f01b166001840152808b60f01b166003840152506bffffffffffffffffffffffff198960601b1660058301528760198301528660398301528560598301528460798301528360998301528251613e338160b9850160208701613c5a565b9190910160b9019b9a5050505050505050505050565b60006101208b835261ffff808c166020850152808b166040850152808a166060850152508760808401528660a08401528560c08401528460e084015280610100840152613e9881840185613c7e565b9c9b505050505050505050505050565b60008251613eba818460208701613c5a565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613efc816017850160208801613c5a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613f39816028840160208801613c5a565b01602801949350505050565b6020815260006134536020830184613c7e565b600060208284031215613f6a57600080fd5b8151613453816138be565b600081613f8457613f84613b62565b50600019019056fea26469706673582212208c88826689fb65a2ff73c9a6a97ae30204bcd092f84237b152ac7ef6778e56e464736f6c634300081300330000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f400000000000000000000000000000000000000000000000000000000000027940000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f4

Deployed Bytecode

0x6080604052600436106102345760003560e01c80637be661bc11610138578063abe685cd116100b0578063c415b95c1161007f578063dd0aef8711610064578063dd0aef8714610816578063e239564b14610836578063e78cea921461085657600080fd5b8063c415b95c146107d6578063d547741f146107f657600080fd5b8063abe685cd1461072e578063b5bfddea14610744578063b7dcdaaa14610778578063c2279cc3146107a957600080fd5b806391df699f116101075780639a8a0592116100ec5780639a8a0592146106e8578063a217fddf14610703578063a86171251461071857600080fd5b806391df699f146106a0578063947b6fdd146106b357600080fd5b80637be661bc146105fc5780638dd148021461061c578063904217c31461063c57806391d148541461065c57600080fd5b806336a141d3116101cb5780635c73da181161019a578063752172cc1161017f578063752172cc146105315780637693402b146105bc5780637b779130146105dc57600080fd5b80635c73da18146104fe578063701a486c1461051e57600080fd5b806336a141d3146104465780633c93adee146104795780634b5cacbc146104b15780635becbd9b146104d157600080fd5b80632ce12669116102075780632ce12669146103755780632f2ff15d146103e45780633380b9831461040657806336568abe1461042657600080fd5b806301ffc9a714610239578063073a559b1461026e5780631f391d7c146102b4578063248a9ca314610345575b600080fd5b34801561024557600080fd5b5061025961025436600461359b565b610876565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a66102893660046135db565b805160208183018101805160038252928201919093012091525481565b604051908152602001610265565b3480156102c057600080fd5b506102d46102cf36600461369e565b6108ad565b604080519c15158d5261ffff9b8c1660208e0152998b16998c019990995296891660608b015297909416608089015260a088019290925260c087015260e08601526101008501526101208401929092526101408301919091526001600160a01b031661016082015261018001610265565b34801561035157600080fd5b506102a66103603660046136c8565b60009081526020819052604090206001015490565b34801561038157600080fd5b506103956103903660046136e1565b610943565b6040516102659190600060a08201905061ffff83511682526001600160a01b03602084015116602083015260408301516040830152606083015160608301526080830151608083015292915050565b3480156103f057600080fd5b506104046103ff366004613711565b6109e3565b005b34801561041257600080fd5b506104046104213660046136c8565b610a0d565b34801561043257600080fd5b50610404610441366004613711565b610a7d565b34801561045257600080fd5b5061046661046136600461369e565b610b0e565b60405161ffff9091168152602001610265565b34801561048557600080fd5b50600754610499906001600160a01b031681565b6040516001600160a01b039091168152602001610265565b3480156104bd57600080fd5b506104046104cc366004613741565b610b55565b3480156104dd57600080fd5b506104f16104ec36600461369e565b610bfe565b604051610265919061375e565b34801561050a57600080fd5b50610404610519366004613793565b610fd2565b6102a661052c3660046137e7565b61109c565b34801561053d57600080fd5b5061058761054c3660046136e1565b600460205260009081526040902080546001820154600283015460039093015461ffff831693620100009093046001600160a01b0316929085565b6040805161ffff90961686526001600160a01b039094166020860152928401919091526060830152608082015260a001610265565b3480156105c857600080fd5b506104046105d73660046136e1565b611290565b3480156105e857600080fd5b506104046105f736600461383d565b6112af565b34801561060857600080fd5b50610404610617366004613880565b6114b7565b34801561062857600080fd5b50610404610637366004613741565b61161a565b34801561064857600080fd5b506104046106573660046138cc565b611655565b34801561066857600080fd5b50610259610677366004613711565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6102a66106ae366004613936565b611742565b3480156106bf57600080fd5b506106d36106ce366004613936565b611dc9565b60408051928352602083019190915201610265565b3480156106f457600080fd5b506005546104669061ffff1681565b34801561070f57600080fd5b506102a6600081565b34801561072457600080fd5b506102a6600a5481565b34801561073a57600080fd5b506102a661271081565b34801561075057600080fd5b506102a67f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f81565b34801561078457600080fd5b506102a66107933660046136e1565b61ffff1660009081526002602052604090205490565b3480156107b557600080fd5b506107c96107c436600461383d565b612036565b6040516102659190613972565b3480156107e257600080fd5b50600854610499906001600160a01b031681565b34801561080257600080fd5b50610404610811366004613711565b61223b565b34801561082257600080fd5b50610404610831366004613a2f565b612260565b34801561084257600080fd5b50610404610851366004613a98565b612759565b34801561086257600080fd5b50600954610499906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b14806108a757506301ffc9a760e01b6001600160e01b03198316145b92915050565b600260205281600052604060002081815481106108c957600080fd5b60009182526020909120600890910201805460018201546002830154600384015460048501546005860154600687015460079097015460ff8716995061ffff61010088048116995063010000008804811698650100000000008904821698600160381b90049091169695949392916001600160a01b03168c565b6109826040518060a00160405280600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b5061ffff908116600090815260046020908152604091829020825160a08101845281549485168152620100009094046001600160a01b0316918401919091526001810154918301919091526002810154606083015260030154608082015290565b6000828152602081905260409020600101546109fe816129bf565b610a0883836129c9565b505050565b6000610a18816129bf565b612710821115610a3b5760405163e7412eeb60e01b815260040160405180910390fd5b600a5460408051918252602082018490527f4f1157e19438bfda32a61ecb89140237e8f062bb9353c62532808b15c860e5a8910160405180910390a150600a55565b6001600160a01b0381163314610b005760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610b0a8282612a67565b5050565b60066020528160005260406000208181548110610b2a57600080fd5b9060005260206000209060109182820401919006600202915091509054906101000a900461ffff1681565b6000610b60816129bf565b6001600160a01b038216610b875760405163133e7b6160e21b815260040160405180910390fd5b600754604080516001600160a01b03928316815291841660208301527f98f22970df215e57c23c0c6140481936298fab08d4b0f0e351cae582921c90a2910160405180910390a1506007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b610c0661357d565b60055461ffff16600090815260066020908152604080832080548251818502810185019093528083529192909190830182828015610c8b57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610c525790505b5050505061ffff861660009081526006602090815260408083208054825181850281018501909352808352959650929490935090830182828015610d1657602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610cdd5790505b505085518451949550600094600160ff1b94509092509050835b82811015610fc557600060046000898481518110610d5057610d50613b12565b60209081029190910181015161ffff90811683528282019390935260409182016000908120835160a08101855281549586168152620100009095046001600160a01b031692850192909252600182015492840192909252600281015460608401526003015460808301529091505b83811015610fbb576000600460008a8481518110610dde57610dde613b12565b602002602001015161ffff1661ffff1681526020019081526020016000206040518060a00160405290816000820160009054906101000a900461ffff1661ffff1661ffff1681526020016000820160029054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600182015481526020016002820154815260200160038201548152505090506000610e8b84600001518f8460000151612036565b9050600760009054906101000a90046001600160a01b03166001600160a01b0316632f8dad4b85600001518f8461010001518561014001518660c001518a60400151886080015161ffff168c606001510281610ee957610ee9613b28565b6040516001600160e01b031960e08a901b16815261ffff90971660048801526024870195909552604486019390935260648501919091526084840152900460a482015260c4016040805180830381865afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613b3e565b5098506000899003610f82575050610fb3565b8c890388811315610faf5760408051808201909152855161ffff908116825284511660208201529c509750875b5050505b600101610dbe565b5050600101610d30565b5050505050505092915050565b6000610fdd816129bf565b6000610fea868686612ae6565b61ffff80881660009081526004602052604090208254600182015493945090928683169261102092600160381b90041690613b78565b61102a9190613b8b565b6001820155815468ffff000000000000001916600160381b61ffff86811691820292909217845560408051898416815292881660208401528201527fcd60dbaa3a0d4b6605e8b3501b72feeeaa1716f70e29bd28a463911b1070547a906060015b60405180910390a150505050505050565b60006110a6612bdf565b60006110b3868686612ae6565b61ffff87166000908152600460205260408120919250806110d5848483612c38565b60095460405163068d8d7d60e21b815261ffff8c1660048201529294509092506001600160a01b0316908190631a3635f490602401602060405180830381865afa158015611127573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114b9190613b9e565b4260026040516020016111619493929190613bdc565b604051602081830303815290604052805190602001209450600960009054906101000a90046001600160a01b03166001600160a01b03166396806f7a348a60028a60028f8e8a8a8f6040516020016111be96959493929190613c15565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016111ec9493929190613caa565b6000604051808303818588803b15801561120557600080fd5b505af1158015611219573d6000803e3d6000fd5b50506040805189815261ffff8e811660208301528d8116828401528c1660608201526080810187905260a0810186905290513394507f50cc914822484a1d459548821999078bf15c508132451f53f92b67132da1139093509081900360c0019150a25050505061128860018055565b949350505050565b61ffff811660009081526004602052604090206112ac90612cca565b50565b60006112ba816129bf565b60006112c7858585612ae6565b805490915060ff16156112ed57604051632a8617b560e21b815260040160405180910390fd5b805460ff1916600117815560055461ffff908116600090815260066020526040808220549287168252812054909190825b828110156113915760055461ffff90811660009081526006602052604090208054918b16918390811061135357611353613b12565b60009182526020909120601082040154600f9091166002026101000a900461ffff160361137f57600193505b8061138981613d04565b91505061131e565b50826113e55760055461ffff9081166000908152600660209081526040822080546001810182559083529120601082040180548b84166002600f909416939093026101000a92830292909302199092161790555b6000925060005b8181101561145c5761ffff88811660009081526006602052604090208054918916918390811061141e5761141e613b12565b60009182526020909120601082040154600f9091166002026101000a900461ffff160361144a57600193505b8061145481613d04565b9150506113ec565b50826114ad5761ffff8088166000908152600660209081526040822080546001810182559083529120601082040180548984166002600f909416939093026101000a92830292909302199092161790555b5050505050505050565b61ffff82166000908152600460205260408120600281018054919284926114df908490613b8b565b92505081905550818160030160008282546114fa9190613b8b565b90915550611509905081612cca565b805460408051637e062a3560e11b81529051611596923392620100009091046001600160a01b0316918691839163fc0c546a916004808201926020929091908290030181865afa158015611561573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115859190613d1d565b6001600160a01b031692919061302f565b80546040516340c10f1960e01b81526001600160a01b0386811660048301526024820185905262010000909204909116906340c10f19906044016020604051808303816000875af11580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190613b9e565b5050505050565b6000611625816129bf565b506009805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b61165d612bdf565b7f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f611687816129bf565b6000611694868989612ae6565b9050848160010160008282546116aa9190613b8b565b909155508390506116cf57848160020160008282546116c99190613b8b565b90915550505b838160060154146116e257600681018490555b6040805161ffff808b16825289166020820152908101869052606081018590527f39c95231d9c33e157609ecd9c4deb49ed4a98afcf489adde59f847a0936c14eb9060800160405180910390a1505061173a60018055565b505050505050565b600061174c612bdf565b600061178361175e60208501856136e1565b61176e60608601604087016136e1565b61177e60408701602088016136e1565b612ae6565b9050600060048161179760208701876136e1565b61ffff1681526020810191909152604001600020825490915060ff166117d05760405163303868b960e21b815260040160405180910390fd5b83606001358260040154116117f85760405163bb55fd2760e01b815260040160405180910390fd5b611866604051806101400160405280600061ffff168152602001600061ffff168152602001600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008019168152602001606081525090565b61187360e0860186613d3a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101208201526007546001600160a01b0316632f8dad4b6118cb60208801886136e1565b876060013586600401548760060154886002015488600101548a60000160079054906101000a900461ffff1661ffff168a6002015461190a9190613d88565b6119149190613d9f565b6040516001600160e01b031960e089901b16815261ffff9096166004870152602486019490945260448501929092526064840152608483015260a482015260c4016040805180830381865afa158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190613b3e565b60a08301526080808301829052860135106119c35760405163428637bb60e11b815260040160405180910390fd5b84606001358360010154116119eb57604051635a39b5af60e11b815260040160405180910390fd5b806080015183600501548460030154611a049190613b8b565b11611a2257604051631dab39a560e31b815260040160405180910390fd5b8060800151836001015411611a4a57604051631dab39a560e31b815260040160405180910390fd5b8060800151836001016000828254611a629190613b78565b90915550506080810151600284018054600090611a80908490613b78565b90915550506080810151600484018054600090611a9e908490613b8b565b925050819055508460600135826003016000828254611abd9190613b8b565b9091555050600a54600283015461271091611ad791613d88565b611ae19190613d9f565b826003015410611af457611af482612cca565b611b0083836001612c38565b60e083015260c0820152815460408051637e062a3560e11b81529051611b66923392620100009091046001600160a01b03169160608a013591839163fc0c546a916004808201926020929091908290030181865afa158015611561573d6000803e3d6000fd5b6009546001600160a01b031680631a3635f4611b886060890160408a016136e1565b6040516001600160e01b031960e084901b16815261ffff9091166004820152602401602060405180830381865afa158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613b9e565b426001604051602001611c019493929190613bdc565b60408051601f1981840301815291815281516020909201919091206101008301526009546001600160a01b0316906396806f7a903490611c479060608a01908a016136e1565b6001611c5960c08b0160a08c01613741565b6001611c6860208d018d6136e1565b611c7860408e0160208f016136e1565b8d60c0016020810190611c8b9190613741565b8a608001518b60a001518c60c001518d60e001518e61010001518f6101200151604051602001611cc49a99989796959493929190613dc1565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611cf29493929190613caa565b6000604051808303818588803b158015611d0b57600080fd5b505af1158015611d1f573d6000803e3d6000fd5b5050506101008301513392507f26fae55a6e1666b8a220d47d475eb9b0e2572a730d4202cb2e0a738a50e910e09150611d5b60208901896136e1565b611d6b60608a0160408b016136e1565b611d7b60408b0160208c016136e1565b8a606001358760a001518860c001518960e001518a6101200151604051611daa99989796959493929190613e49565b60405180910390a2610100015192505050611dc460018055565b919050565b60008080611dfd611ddd60208601866136e1565b611ded60608701604088016136e1565b61177e60408801602089016136e1565b90506000600481611e1160208801886136e1565b61ffff1681526020810191909152604001600020825490915060ff16611e4a5760405163303868b960e21b815260040160405180910390fd5b8460600135826004015411611e7257604051634323a55560e01b815260040160405180910390fd5b611ee0604051806101400160405280600061ffff168152602001600061ffff168152602001600061ffff16815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008019168152602001606081525090565b6007546001600160a01b0316632f8dad4b611efe60208901896136e1565b886060013586600401548760060154886002015488600101548a60000160079054906101000a900461ffff1661ffff168a60020154611f3d9190613d88565b611f479190613d9f565b6040516001600160e01b031960e089901b16815261ffff9096166004870152602486019490945260448501929092526064840152608483015260a482015260c4016040805180830381865afa158015611fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc89190613b3e565b6001850154919650945060608701351115611ff657604051635a39b5af60e11b815260040160405180910390fd5b80608001518360050154846003015461200f9190613b8b565b101561202e57604051631dab39a560e31b815260040160405180910390fd5b505050915091565b604080516101808101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261ffff8716825260028152838220935160f088811b6001600160f01b03199081169383019390935287811b8316602283015286901b90911660248201529192909160039060260160408051601f19818403018152908290526120f891613ea8565b9081526020016040518091039020548154811061211757612117613b12565b60009182526020909120600890910201805490915061ffff858116630100000090920416146121595760405163069cd95760e41b815260040160405180910390fd5b805461ffff84811665010000000000909204161461218a5760405163069cd95760e41b815260040160405180910390fd5b6040805161018081018252825460ff81161515825261ffff610100808304821660208501526301000000830482169484019490945265010000000000820481166060840152600160381b909104166080820152600183015460a0820152600283015460c0820152600383015460e0820152600483015491810191909152600582015461012082015260068201546101408201526007909101546001600160a01b031661016082015290509392505050565b600082815260208190526040902060010154612256816129bf565b610a088383612a67565b600061226b816129bf565b61ffff8616600090815260026020526040812054905b818110156123cf5761ffff881660009081526002602052604081208054839081106122ae576122ae613b12565b600091825260208083206040805161018081018252600894909402909101805460ff81161515855261010080820461ffff9081169587019590955263010000008204851693860184905265010000000000820485166060870152600160381b90910484166080860152600182015460a0860152600282015460c0860152600382015460e086015260048201549085015260058101546101208501526006810154610140850152600701546001600160a01b03166101608401529193508a1614801561238457508761ffff16826060015161ffff16145b801561239b57508961ffff16826020015161ffff16145b905080156123bc57604051632a8617b560e21b815260040160405180910390fd5b5050806123c890613d04565b9050612281565b5061ffff87166000908152600460205260409020546201000090046001600160a01b0316612491576040805160a08101825261ffff808a168083526001600160a01b03808816602080860191825260008688018181526060880182815260808901838152968352600490935297902095518654925190931662010000027fffffffffffffffffffff0000000000000000000000000000000000000000000090921692909416919091171783559251600183015551600282015590516003909101555b61ffff87811660009081526004602052604081206001018054928716929091906124bc908490613b8b565b909155505061ffff87166000908152600260209081526040918290205491516001600160f01b031960f08b811b82169383019390935289831b811660228301529188901b909116602482015260039060260160408051601f198184030181529082905261252891613ea8565b908152602001604051809103902081905550600260008861ffff1661ffff1681526020019081526020016000206040518061018001604052806000151581526020018961ffff1681526020018861ffff1681526020018761ffff1681526020018661ffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001856001600160a01b0316815250908060018154018082558091505060019003906000526020600020906008020160009091909190915060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548161ffff021916908361ffff16021790555060608201518160000160056101000a81548161ffff021916908361ffff16021790555060808201518160000160076101000a81548161ffff021916908361ffff16021790555060a0820151816001015560c0820151816002015560e082015181600301556101008201518160040155610120820151816005015561014082015181600601556101608201518160070160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555050507fcd60dbaa3a0d4b6605e8b3501b72feeeaa1716f70e29bd28a463911b1070547a86868660405161108b9392919061ffff93841681529183166020830152909116604082015260600190565b612761612bdf565b7f52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f61278b816129bf565b600061279889898c6130a4565b61ffff8a16600090815260046020526040812060018301805493945090928792906127c4908490613b8b565b9091555050600682015484146127dc57600682018490555b6040805161ffff808c1682528d166020820152908101869052606081018590527f39c95231d9c33e157609ecd9c4deb49ed4a98afcf489adde59f847a0936c14eb9060800160405180910390a18682600301600082825461283d9190613b78565b92505081905550868260040160008282546128589190613b78565b92505081905550868260020160008282546128739190613b8b565b90915550508054604051630357371d60e01b81526001600160a01b038a81166004830152602482018a90526201000090920490911690630357371d90604401600060405180830381600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050506000861180156128fe57506008546001600160a01b031615155b15612950576040518681527fc472cb3a7a659a876494d66b3063145f279701771d6150b9329c31611ed6405c9060200160405180910390a18581600201600082825461294a9190613b8b565b90915550505b6040805161ffff8d811682528c811660208301528b16818301526001600160a01b038a1660608201526080810189905260a0810188905290517fcffd018da5de203cecdd9ba279e59cc5dc6ed918472a4a012beb369c7e09fe349181900360c00190a15050506114ad60018055565b6112ac8133613140565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610b0a576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612a233390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610b0a576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b61ffff8316600090815260026020908152604080832090516001600160f01b031960f088811b82169483019490945286841b811660228301529285901b9092166024830152829160039060260160408051601f1981840301815290829052612b4d91613ea8565b90815260200160405180910390205481548110612b6c57612b6c613b12565b60009182526020909120600890910201805490915061ffff85811663010000009092041614612bae5760405163069cd95760e41b815260040160405180910390fd5b805461ffff8481166501000000000090920416146112885760405163069cd95760e41b815260040160405180910390fd5b600260015403612c315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610af7565b6002600155565b8254600090819060ff16612c5f5760405163303868b960e21b815260040160405180910390fd5b6005850154600386018054909101905582612c8557600585015460048601805490910190555b60058501805460009091556001850154865460028701549294509091612cb691600160381b900461ffff1690613d88565b612cc09190613d9f565b9050935093915050565b6003810154600182015415610b0a57815461ffff16600090815260026020526040812054908167ffffffffffffffff811115612d0857612d086135c5565b604051908082528060200260200182016040528015612d31578160200160208202803683370190505b5090506000805b83811015612e1557855461ffff166000908152600260205260408120805483908110612d6657612d66613b12565b60009182526020822060018a015460089290920201805460028b0154919450612d9b91600160381b90910461ffff1690613d88565b612da59190613d9f565b9050600082600501548360030154612dbd9190613b8b565b905080821115612e0757808203868581518110612ddc57612ddc613b12565b602002602001018181525050858481518110612dfa57612dfa613b12565b6020026020010151850194505b836001019350505050612d38565b50600081158015612e265750600085115b15612eba5760005b84811015612eb457865461ffff166000908152600260205260408120805483908110612e5c57612e5c613b12565b60009182526020822060018b015460089290920201805460038c0154919450612e9191600160381b90910461ffff1690613d88565b612e9b9190613d9f565b6005909201805483019055509190910190600101612e2e565b5061300e565b848211612f5d5760005b84811015612eb4576000848281518110612ee057612ee0613b12565b60200260200101511115612f5557865461ffff166000908152600260205260408120805483908110612f1457612f14613b12565b906000526020600020906008020190506000858381518110612f3857612f38613b12565b602090810291909101015160059092018054830190555091909101905b600101612ec4565b60005b8481101561300c576000848281518110612f7c57612f7c613b12565b6020026020010151111561300457865461ffff166000908152600260205260408120805483908110612fb057612fb0613b12565b9060005260206000209060080201905060008488878581518110612fd657612fd6613b12565b6020026020010151612fe89190613d88565b612ff29190613d9f565b60059092018054830190555091909101905b600101612f60565b505b808660030160008282546130229190613b78565b9091555050505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905261309e9085906131b3565b50505050565b61ffff8316600090815260026020908152604080832090516001600160f01b031960f088811b82169483019490945286841b811660228301529285901b90921660248301529060039060260160408051601f198184030181529082905261310a91613ea8565b9081526020016040518091039020548154811061312957613129613b12565b906000526020600020906008020190509392505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610b0a5761317181613298565b61317c8360206132aa565b60405160200161318d929190613ec4565b60408051601f198184030181529082905262461bcd60e51b8252610af791600401613f45565b6000613208826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661345a9092919063ffffffff16565b805190915015610a0857808060200190518101906132269190613f58565b610a085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610af7565b60606108a76001600160a01b03831660145b606060006132b9836002613d88565b6132c4906002613b8b565b67ffffffffffffffff8111156132dc576132dc6135c5565b6040519080825280601f01601f191660200182016040528015613306576020820181803683370190505b509050600360fc1b8160008151811061332157613321613b12565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061335057613350613b12565b60200101906001600160f81b031916908160001a9053506000613374846002613d88565b61337f906001613b8b565b90505b6001811115613404577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106133c0576133c0613b12565b1a60f81b8282815181106133d6576133d6613b12565b60200101906001600160f81b031916908160001a90535060049490941c936133fd81613f75565b9050613382565b5083156134535760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610af7565b9392505050565b6060611288848460008585600080866001600160a01b031685876040516134819190613ea8565b60006040518083038185875af1925050503d80600081146134be576040519150601f19603f3d011682016040523d82523d6000602084013e6134c3565b606091505b50915091506134d4878383876134df565b979650505050505050565b6060831561354e578251600003613547576001600160a01b0385163b6135475760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610af7565b5081611288565b61128883838151156135635781518083602001fd5b8060405162461bcd60e51b8152600401610af79190613f45565b60405180604001604052806002906020820280368337509192915050565b6000602082840312156135ad57600080fd5b81356001600160e01b03198116811461345357600080fd5b634e487b7160e01b600052604160045260246000fd5b6000602082840312156135ed57600080fd5b813567ffffffffffffffff8082111561360557600080fd5b818401915084601f83011261361957600080fd5b81358181111561362b5761362b6135c5565b604051601f8201601f19908116603f01168101908382118183101715613653576136536135c5565b8160405282815287602084870101111561366c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b803561ffff81168114611dc457600080fd5b600080604083850312156136b157600080fd5b6136ba8361368c565b946020939093013593505050565b6000602082840312156136da57600080fd5b5035919050565b6000602082840312156136f357600080fd5b6134538261368c565b6001600160a01b03811681146112ac57600080fd5b6000806040838503121561372457600080fd5b823591506020830135613736816136fc565b809150509250929050565b60006020828403121561375357600080fd5b8135613453816136fc565b60408101818360005b600281101561378a57815161ffff16835260209283019290910190600101613767565b50505092915050565b600080600080608085870312156137a957600080fd5b6137b28561368c565b93506137c06020860161368c565b92506137ce6040860161368c565b91506137dc6060860161368c565b905092959194509250565b600080600080608085870312156137fd57600080fd5b6138068561368c565b93506138146020860161368c565b92506138226040860161368c565b91506060850135613832816136fc565b939692955090935050565b60008060006060848603121561385257600080fd5b61385b8461368c565b92506138696020850161368c565b91506138776040850161368c565b90509250925092565b60008060006060848603121561389557600080fd5b83356138a0816136fc565b92506138ae6020850161368c565b9150604084013590509250925092565b80151581146112ac57600080fd5b60008060008060008060c087890312156138e557600080fd5b6138ee8761368c565b95506138fc6020880161368c565b945061390a6040880161368c565b9350606087013592506080870135915060a0870135613928816138be565b809150509295509295509295565b60006020828403121561394857600080fd5b813567ffffffffffffffff81111561395f57600080fd5b8201610100818503121561345357600080fd5b81511515815261018081016020830151613992602084018261ffff169052565b5060408301516139a8604084018261ffff169052565b5060608301516139be606084018261ffff169052565b5060808301516139d4608084018261ffff169052565b5060a0838101519083015260c0808401519083015260e08084015190830152610100808401519083015261012080840151908301526101408084015190830152610160928301516001600160a01b0316929091019190915290565b600080600080600060a08688031215613a4757600080fd5b613a508661368c565b9450613a5e6020870161368c565b9350613a6c6040870161368c565b9250613a7a6060870161368c565b91506080860135613a8a816136fc565b809150509295509295909350565b600080600080600080600080610100898b031215613ab557600080fd5b613abe8961368c565b9750613acc60208a0161368c565b9650613ada60408a0161368c565b95506060890135613aea816136fc565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008060408385031215613b5157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b818103818111156108a7576108a7613b62565b808201808211156108a7576108a7613b62565b600060208284031215613bb057600080fd5b5051919050565b60038110613bd557634e487b7160e01b600052602160045260246000fd5b60f81b9052565b6bffffffffffffffffffffffff198560601b168152836014820152826034820152613c0a6054820183613bb7565b605501949350505050565b613c1f8188613bb7565b6001600160f01b031960f096871b811660018301529490951b9093166003850152600584019190915260258301526045820152606501919050565b60005b83811015613c75578181015183820152602001613c5d565b50506000910152565b60008151808452613c96816020860160208601613c5a565b601f01601f19169290920160200192915050565b61ffff85168152600060038510613cd157634e487b7160e01b600052602160045260246000fd5b8460208301526001600160a01b038416604083015260806060830152613cfa6080830184613c7e565b9695505050505050565b600060018201613d1657613d16613b62565b5060010190565b600060208284031215613d2f57600080fd5b8151613453816136fc565b6000808335601e19843603018112613d5157600080fd5b83018035915067ffffffffffffffff821115613d6c57600080fd5b602001915036819003821315613d8157600080fd5b9250929050565b80820281158282048414176108a7576108a7613b62565b600082613dbc57634e487b7160e01b600052601260045260246000fd5b500490565b613dcb818c613bb7565b600061ffff60f01b808c60f01b166001840152808b60f01b166003840152506bffffffffffffffffffffffff198960601b1660058301528760198301528660398301528560598301528460798301528360998301528251613e338160b9850160208701613c5a565b9190910160b9019b9a5050505050505050505050565b60006101208b835261ffff808c166020850152808b166040850152808a166060850152508760808401528660a08401528560c08401528460e084015280610100840152613e9881840185613c7e565b9c9b505050505050505050505050565b60008251613eba818460208701613c5a565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613efc816017850160208801613c5a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613f39816028840160208801613c5a565b01602801949350505050565b6020815260006134536020830184613c7e565b600060208284031215613f6a57600080fd5b8151613453816138be565b600081613f8457613f84613b62565b50600019019056fea26469706673582212208c88826689fb65a2ff73c9a6a97ae30204bcd092f84237b152ac7ef6778e56e464736f6c63430008130033

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

0000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f400000000000000000000000000000000000000000000000000000000000027940000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f4

-----Decoded View---------------
Arg [0] : _feeHandler (address): 0x0c53Ca3B4069800c71D9aB1EC555F6f4975861f4
Arg [1] : _chainId (uint16): 10132
Arg [2] : _feeCollector (address): 0x0c53Ca3B4069800c71D9aB1EC555F6f4975861f4

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f4
Arg [1] : 0000000000000000000000000000000000000000000000000000000000002794
Arg [2] : 0000000000000000000000000c53ca3b4069800c71d9ab1ec555f6f4975861f4


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading