S Price: $0.770827 (-4.55%)

Token

SonicBank (BANK)

Overview

Max Total Supply

171,900.757152722857018806 BANK

Holders

357

Market

Price

$0.00 @ 0.000000 S

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
208.843258307512693909 BANK

Value
$0.00
0x34dd708de24209c61572161a89a7667c0e64e284
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
SonicBank

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at SonicScan.org on 2025-02-24
*/

// File: contracts/Context.sol

pragma solidity ^0.8.0;

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: interfaces/IAccessControl.sol

pragma solidity ^0.8.0;

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: interfaces/IAccessControlEnumerable.sol

pragma solidity ^0.8.0;


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

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

pragma solidity ^0.8.0;


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: contracts/ERC165.sol

pragma solidity ^0.8.0;


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: libraries/Math.sol

pragma solidity ^0.8.0;


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: libraries/SignedMath.sol

pragma solidity ^0.8.0;


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

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

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

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

pragma solidity ^0.8.0;



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: contracts/AccessControl.sol

pragma solidity ^0.8.0;





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: libraries/EnumerableSet.sol

pragma solidity ^0.8.0;

library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

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

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

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

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

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

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

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

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

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

            return true;
        } else {
            return false; 
        }
    }

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

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

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

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

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

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

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

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

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

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

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

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

        return result;
    }
}
// File: contracts/AccessControlEnumerable.sol

pragma solidity ^0.8.0;




abstract contract AccessControlEnumerable is
    IAccessControlEnumerable,
    AccessControl
{
    using EnumerableSet for EnumerableSet.AddressSet;

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

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

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

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

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

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

pragma solidity ^0.8.0;


// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

/**
 * @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: interfaces/IERC20MetaData.sol

pragma solidity ^0.8.0;


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: contracts/ERC20.sol

pragma solidity ^0.8.0;





contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account)
        public
        view
        virtual
        override
        returns (uint256)
    {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount)
        public
        virtual
        override
        returns (bool)
    {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender)
        public
        view
        virtual
        override
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount)
        public
        virtual
        override
        returns (bool)
    {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue)
        public
        virtual
        returns (bool)
    {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
        public
        virtual
        returns (bool)
    {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(
            currentAllowance >= subtractedValue,
            "ERC20: decreased allowance below zero"
        );
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(
            fromBalance >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(
                currentAllowance >= amount,
                "ERC20: insufficient allowance"
            );
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}
// File: contracts/ERC20Burnable.sol

pragma solidity ^0.8.0;



abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        _spendAllowance(account, _msgSender(), amount);
        _burn(account, amount);
    }
}
// File: contracts/ERC20PresetMinterRebaser.sol

pragma solidity ^0.8.0;




contract ERC20PresetMinterRebaser is
    Context,
    AccessControlEnumerable,
    ERC20Burnable
{
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant REBASER_ROLE = keccak256("REBASER_ROLE");

    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());

        _setupRole(MINTER_ROLE, _msgSender());
        _setupRole(REBASER_ROLE, _msgSender());
    }
}
// File: contracts/Ownable.sol

pragma solidity ^0.8.0;


abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
// File: contracts/IBTC.sol

pragma solidity ^0.8.0;

abstract contract IBTC {
    event Rebase(
        uint256 epoch,
        uint256 prevbtcsScalingFactor,
        uint256 newbtcsScalingFactor
    );
    event Mint(address to, uint256 amount);
    event Burn(address from, uint256 amount);
}
// File: libraries/SafeMath.sol

pragma solidity ^0.8.0;

library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
// File: interfaces/ILP.sol

pragma solidity ^0.8.0;


interface ILP {
    function sync() external;
}


// File: contracts/SonicBank.sol

pragma solidity ^0.8.0;







contract SonicBank is ERC20PresetMinterRebaser, Ownable, IBTC {
    using SafeMath for uint256;

    /**
     * @dev Guard variable for re-entrancy checks. Not currently used
     */
    bool internal _notEntered;

    /**
     * @notice Internal decimals used to handle scaling factor
     */
    uint256 public constant internalDecimals = 10**24;

    /**
     * @notice Used for percentage maths
     */
    uint256 public constant BASE = 10**18;

    /**
     * @notice Scaling factor that adjusts everyone's balances
     */
    uint256 public btcsScalingFactor;
 
    mapping(address => uint256) internal _btcBalances;

    mapping(address => mapping(address => uint256)) internal _allowedFragments;
    ILP public LPpool;
    uint256 public initSupply;
    uint256 public rebaseRatio = 100;
    address public treasury = address(0);
    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 public constant PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    bytes32 public DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH =
        keccak256(
            "EIP712Domain(string name,uint256 chainId,address verifyingContract)"
        );

    uint256 private INIT_SUPPLY = 600000 * 10**18;
    uint256 private _totalSupply;
    
    modifier validRecipient(address to) {
        require(to != address(0x0));
        require(to != address(this));
        _;
    }

    bool public isTradingLive;

    address team;


    uint256 public maxTransaction;
    uint256 public maxWallet;

    uint256 public maxTransactionFrag;
    uint256 public maxWalletFrag;

    uint256 public MAX_TRANSACTION_PERCENT = 50; // 0.5%
    uint256 public MAX_WALLET_PERCENT = 100; // 1%

    bool public limitsInEffect = true;
    bool public tradingActive = false;

    mapping(address => bool) private _isExcludedFromFees;
    mapping(address => bool) public _isExcludedmaxTransaction;
    mapping(address => bool) public automatedMarketMakerPairs;

    constructor() ERC20PresetMinterRebaser("SonicBank", "BANK") {
        btcsScalingFactor = BASE;
        initSupply = _fragmentTobtc(INIT_SUPPLY);
        _totalSupply = INIT_SUPPLY;
        _btcBalances[owner()] = initSupply;
        uint256 LPSupply = 200000 * 10**18;
        team = msg.sender;

        maxTransaction = (LPSupply * MAX_TRANSACTION_PERCENT) / 10_000;
        maxWallet = (LPSupply * MAX_WALLET_PERCENT) / 10_000;

        maxTransactionFrag = _fragmentTobtc(maxTransaction);
        maxWalletFrag = _fragmentTobtc(maxWallet);


        excludeFromMaxTransaction(owner(), true);
        excludeFromMaxTransaction(address(this), true);
        excludeFromMaxTransaction(address(0xdead), true);

        excludeFromFees(owner(), true);
        excludeFromFees(address(this), true);
        excludeFromFees(address(0xdead), true);

        emit Transfer(address(0), msg.sender, INIT_SUPPLY);
    }

    /**
     * @return The total number of fragments.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    function setLP(ILP LP) public onlyOwner {
        LPpool = LP;
    }

    /**
     * @notice Computes the current max scaling factor
     */
    function maxScalingFactor() external view returns (uint256) {
        return _maxScalingFactor();
    }

    function _maxScalingFactor() internal view returns (uint256) {
        // scaling factor can only go up to 2**256-1 = initSupply * btcsScalingFactor
        // this is used to check if btcsScalingFactor will be too high to compute balances when rebasing.
        return uint256(int256(-1)) / initSupply;
    }

    /**
     * @notice Mints new tokens, increasing totalSupply, initSupply, and a users balance.
     */
    function mint(address to, uint256 amount) external returns (bool) {
        require(hasRole(MINTER_ROLE, _msgSender()), "Must have minter role");

        _mint(to, amount);
        return true;
    }

    function _mint(address to, uint256 amount) internal override {
        // increase totalSupply
        _totalSupply = _totalSupply.add(amount);

        // get underlying value
        uint256 btcValue = _fragmentTobtc(amount);

        // increase initSupply
        initSupply = initSupply.add(btcValue);

        // make sure the mint didnt push maxScalingFactor too low
        require(
            btcsScalingFactor <= _maxScalingFactor(),
            "max scaling factor too low"
        );

        // add balance
        _btcBalances[to] = _btcBalances[to].add(btcValue);

        emit Mint(to, amount);
        emit Transfer(address(0), to, amount);
    }

    /**
     * @notice Burns tokens from msg.sender, decreases totalSupply, initSupply, and a users balance.
     */

    function burn(uint256 amount) public override {
        _burn(amount);
    }

    function _burn(uint256 amount) internal {
        // decrease totalSupply
        _totalSupply = _totalSupply.sub(amount);

        // get underlying value
        uint256 btcValue = _fragmentTobtc(amount);

        // decrease initSupply
        initSupply = initSupply.sub(btcValue);

        // decrease balance
        _btcBalances[msg.sender] = _btcBalances[msg.sender].sub(btcValue);
        emit Burn(msg.sender, amount);
        emit Transfer(msg.sender, address(0), amount);
    }

    /**
     * @notice Mints new tokens using underlying amount, increasing totalSupply, initSupply, and a users balance.
     */
    function mintUnderlying(address to, uint256 amount) public returns (bool) {
        require(hasRole(MINTER_ROLE, _msgSender()), "Must have minter role");

        _mintUnderlying(to, amount);
        return true;
    }

    function _mintUnderlying(address to, uint256 amount) internal {
        // increase initSupply
        initSupply = initSupply.add(amount);

        // get external value
        uint256 scaledAmount = _btcToFragment(amount);

        // increase totalSupply
        _totalSupply = _totalSupply.add(scaledAmount);

        // make sure the mint didnt push maxScalingFactor too low
        require(
            btcsScalingFactor <= _maxScalingFactor(),
            "max scaling factor too low"
        );

        // add balance
        _btcBalances[to] = _btcBalances[to].add(amount);

        emit Mint(to, scaledAmount);
        emit Transfer(address(0), to, scaledAmount);
    }

    /**
     * @dev Transfer underlying balance to a specified address.
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     * @return True on success, false otherwise.
     */
    function transferUnderlying(address to, uint256 value)
        public
        validRecipient(to)
        returns (bool)
    {
        // sub from balance of sender
        _btcBalances[msg.sender] = _btcBalances[msg.sender].sub(value);

        // add to balance of receiver
        _btcBalances[to] = _btcBalances[to].add(value);
        emit Transfer(msg.sender, to, _btcToFragment(value));
        return true;
    }

    /* - ERC20 functionality - */



     
    function _transfer(address from, address to, uint256 value)
        internal
        override
        validRecipient(to)
    {
        // underlying balance is stored in btcs, so divide by current scaling factor

        // note, this means as scaling factor grows, dust will be untransferrable.
        // minimum transfer value == btcsScalingFactor / 1e24;

        // get amount in underlying
        uint256 btcValue = _fragmentTobtc(value);

        if (limitsInEffect) {
		      if (from != owner() && to != owner() && to != address(0xdead)) {
		        if (!tradingActive) {
		          require(_isExcludedFromFees[from] || _isExcludedFromFees[to], "Trading is not active.");
			    }

		        // BUY
		        if (automatedMarketMakerPairs[from] && !_isExcludedmaxTransaction[to]) {
			        require(btcValue <= maxTransactionFrag, "Buy transfer amount exceeds the maxTransaction.");
			        require(btcValue + balanceOfUnderlying(to) <= maxWalletFrag, "Max wallet exceeded");
		        }
		        // SELL
		        else if (automatedMarketMakerPairs[to] && !_isExcludedmaxTransaction[from]) {
			        require(btcValue <= maxTransactionFrag, "Sell transfer amount exceeds the maxTransaction.");
		        } else if (!_isExcludedmaxTransaction[to]) {
			        require(btcValue + balanceOfUnderlying(to) <= maxWalletFrag, "Max wallet exceeded");
		        }
		    }
		}

        // sub from balance of sender
        _btcBalances[from] = _btcBalances[from].sub(btcValue);

        // add to balance of receiver
        _btcBalances[to] = _btcBalances[to].add(btcValue);
        emit Transfer(from, to, value);

    }

    /**
     * @dev Transfer tokens from one address to another.
     * @param from The address you want to send tokens from.
     * @param to The address you want to transfer to.
     * @param value The amount of tokens to be transferred.
     */
    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public override validRecipient(to) returns (bool) {
        // decrease allowance
        _allowedFragments[from][msg.sender] = _allowedFragments[from][
            msg.sender
        ].sub(value);

        // get value in btcs
        uint256 btcValue = _fragmentTobtc(value);

        // sub from from
        _btcBalances[from] = _btcBalances[from].sub(btcValue);
        _btcBalances[to] = _btcBalances[to].add(btcValue);
        emit Transfer(from, to, value);

        return true;
    }

    /**
     * @param who The address to query.
     * @return The balance of the specified address.
     */
    function balanceOf(address who) public view override returns (uint256) {
        return _btcToFragment(_btcBalances[who]);
    }

    /** @notice Currently returns the internal storage amount
     * @param who The address to query.
     * @return The underlying balance of the specified address.
     */
    function balanceOfUnderlying(address who) public view returns (uint256) {
        return _btcBalances[who];
    }

    /**
     * @dev Function to check the amount of tokens that an owner has allowed to a spender.
     * @param owner_ The address which owns the funds.
     * @param spender The address which will spend the funds.
     * @return The number of tokens still available for the spender.
     */
    function allowance(address owner_, address spender)
        public
        view
        override
        returns (uint256)
    {
        return _allowedFragments[owner_][spender];
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of
     * msg.sender. This method is included for ERC20 compatibility.
     * increaseAllowance and decreaseAllowance should be used instead.
     * Changing an allowance with this method brings the risk that someone may transfer both
     * the old and the new allowance - if they are both greater than zero - if a transfer
     * transaction is mined before the later approve() call is mined.
     *
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function approve(address spender, uint256 value)
        public
        override
        returns (bool)
    {
        _allowedFragments[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Increase the amount of tokens that an owner has allowed to a spender.
     * This method should be used instead of approve() to avoid the double approval vulnerability
     * described above.
     * @param spender The address which will spend the funds.
     * @param addedValue The amount of tokens to increase the allowance by.
     */
    function increaseAllowance(address spender, uint256 addedValue)
        public
        override
        returns (bool)
    {
        _allowedFragments[msg.sender][spender] = _allowedFragments[msg.sender][
            spender
        ].add(addedValue);
        emit Approval(
            msg.sender,
            spender,
            _allowedFragments[msg.sender][spender]
        );
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner has allowed to a spender.
     *
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
        public
        override
        returns (bool)
    {
        uint256 oldValue = _allowedFragments[msg.sender][spender];
        if (subtractedValue >= oldValue) {
            _allowedFragments[msg.sender][spender] = 0;
        } else {
            _allowedFragments[msg.sender][spender] = oldValue.sub(
                subtractedValue
            );
        }
        emit Approval(
            msg.sender,
            spender,
            _allowedFragments[msg.sender][spender]
        );
        return true;
    }

    // --- Approve by signature ---
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public {
        require(block.timestamp <= deadline, "btc/permit-expired");

        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(
                    abi.encode(
                        PERMIT_TYPEHASH,
                        owner,
                        spender,
                        value,
                        nonces[owner]++,
                        deadline
                    )
                )
            )
        );

        require(owner != address(0), "btc/invalid-address-0");
        require(owner == ecrecover(digest, v, r, s), "btc/invalid-permit");
        _allowedFragments[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function rebase(
        uint256 epoch,
        uint256 indexDelta,
        bool positive
    ) public returns (uint256) {
        require(hasRole(REBASER_ROLE, _msgSender()), "Must have rebaser role");

        // no change
        if (indexDelta == 0) {
            emit Rebase(epoch, btcsScalingFactor, btcsScalingFactor);
            return _totalSupply;
        }

        // for events
        uint256 prevbtcsScalingFactor = btcsScalingFactor;

        if (!positive) {
            // negative rebase, decrease scaling factor
            btcsScalingFactor = btcsScalingFactor
                .mul(BASE.sub(indexDelta))
                .div(BASE);
        } else {
            // positive rebase, increase scaling factor
            uint256 newScalingFactor = btcsScalingFactor
                .mul(BASE.add(indexDelta))
                .div(BASE);
            if (newScalingFactor < _maxScalingFactor()) {
                btcsScalingFactor = newScalingFactor;
            } else {
                btcsScalingFactor = _maxScalingFactor();
            }
        }

        // update total supply, correctly
        _totalSupply = _btcToFragment(initSupply);

        if (address(LPpool) != address(0)){
            LPpool.sync();
        }
        

        emit Rebase(epoch, prevbtcsScalingFactor, btcsScalingFactor);
        return _totalSupply;
    }

    function _rebase(
        uint256 epoch,
        uint256 indexDelta,
        bool positive
    ) internal returns (uint256) {

        // no change
        if (indexDelta == 0) {
            emit Rebase(epoch, btcsScalingFactor, btcsScalingFactor);
            return _totalSupply;
        }

        // for events
        uint256 prevbtcsScalingFactor = btcsScalingFactor;

        if (!positive) {
            // negative rebase, decrease scaling factor
            btcsScalingFactor = btcsScalingFactor
                .mul(BASE.sub(indexDelta))
                .div(BASE);
        } else {
            // positive rebase, increase scaling factor
            uint256 newScalingFactor = btcsScalingFactor
                .mul(BASE.add(indexDelta))
                .div(BASE);
            if (newScalingFactor < _maxScalingFactor()) {
                btcsScalingFactor = newScalingFactor;
            } else {
                btcsScalingFactor = _maxScalingFactor();
            }
        }

        // update total supply, correctly
        _totalSupply = _btcToFragment(initSupply);
        if (address(LPpool) != address(0)){
            LPpool.sync();
        }
        

        emit Rebase(epoch, prevbtcsScalingFactor, btcsScalingFactor);
        return _totalSupply;
    }


    function _claimtokensWRebase(address _address, uint256 amount) internal {
        require(hasRole(MINTER_ROLE, _msgSender()), "Must have minter role");
        uint256 ratio = amount*1e18*rebaseRatio/(100*totalSupply());
        _mint(_address, amount);
        _rebase(0, ratio, false);
    }

    function claimtokenRebase(address _address, uint256 amount) external {
        require(hasRole(MINTER_ROLE, _msgSender()), "Must have minter role");
        _claimtokensWRebase(_address, amount);
    }

    function updateRebaseRatio(uint256 _newratio) external onlyOwner{
        require(_newratio <= 100);
        rebaseRatio = _newratio;
    }

    function updateTreasury(address _newaddress) external onlyOwner{
        treasury = _newaddress;
    }


    function btcToFragment(uint256 _btc) public view returns (uint256) {
        return _btcToFragment(_btc);
    }

    function fragmentTobtc(uint256 value) public view returns (uint256) {
        return _fragmentTobtc(value);
    }

    function _btcToFragment(uint256 _btc) internal view returns (uint256) {
        return _btc.mul(btcsScalingFactor).div(internalDecimals);
    }

    function _fragmentTobtc(uint256 value) internal view returns (uint256) {
        return value.mul(internalDecimals).div(btcsScalingFactor);
    }

    function removeLimits() external onlyOwner {
        limitsInEffect = false;
    }

    function excludeFromMaxTransaction(address updAds, bool isEx) public onlyOwner {
        _isExcludedmaxTransaction[updAds] = isEx;
    }

    function excludeFromFees(address account, bool excluded) public onlyOwner {
        _isExcludedFromFees[account] = excluded;
    }

    function enableTrading() external onlyOwner {
        require(!tradingActive, "Token launched");
        tradingActive = true;
    }

    function setAutomatedMarketMakerPair(address pair, bool value) public onlyOwner {
        automatedMarketMakerPairs[pair] = value;
    }

    // Withdraw ERC20 tokens that are potentially stuck in Contract
    function recoverTokensFromContract(address _tokenAddress, uint256 _amount) external onlyOwner {
        bool succ = ERC20(_tokenAddress).transfer(team, _amount);
        require(succ, "Transfer failed");
    }

}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prevbtcsScalingFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newbtcsScalingFactor","type":"uint256"}],"name":"Rebase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LPpool","outputs":[{"internalType":"contract ILP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TRANSACTION_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_WALLET_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REBASER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_isExcludedmaxTransaction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"automatedMarketMakerPairs","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_btc","type":"uint256"}],"name":"btcToFragment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"btcsScalingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimtokenRebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableTrading","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"excluded","type":"bool"}],"name":"excludeFromFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"updAds","type":"address"},{"internalType":"bool","name":"isEx","type":"bool"}],"name":"excludeFromMaxTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"fragmentTobtc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"internalDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTradingLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitsInEffect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxScalingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTransaction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTransactionFrag","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxWalletFrag","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintUnderlying","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"indexDelta","type":"uint256"},{"internalType":"bool","name":"positive","type":"bool"}],"name":"rebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebaseRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverTokensFromContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","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":"address","name":"pair","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setAutomatedMarketMakerPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILP","name":"LP","type":"address"}],"name":"setLP","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":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferUnderlying","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newratio","type":"uint256"}],"name":"updateRebaseRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newaddress","type":"address"}],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040526064600d819055600e80546001600160a01b0319169055697f0e10af47c1c70000006011556032601855601955601a805461ffff191660011790553480156200004b575f80fd5b5060405180604001604052806009815260200168536f6e696342616e6b60b81b8152506040518060400160405280600481526020016342414e4b60e01b815250818181600590816200009e9190620005f4565b506006620000ad8282620005f4565b50620000be91505f905033620002b8565b620000ea7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a633620002b8565b620001167f5fde63b561377d1441afa201ff619faac2ff8fed70a7fbdbe7a5cb07768c0b7533620002b8565b5062000124905033620002c8565b670de0b6b3a76400006008556011546200013e9062000319565b600c81905560115460125560095f6200015f6007546001600160a01b031690565b6001600160a01b0316815260208101919091526040015f205560138054610100600160a81b0319163361010002179055601854692a5a058fc295ed0000009061271090620001ae9083620006c0565b620001ba9190620006e4565b60145560195461271090620001d09083620006c0565b620001dc9190620006e4565b601555601454620001ed9062000319565b601655601554620001fe9062000319565b60175562000220620002186007546001600160a01b031690565b600162000346565b6200022d30600162000346565b6200023c61dead600162000346565b6200025b620002536007546001600160a01b031690565b60016200037a565b620002683060016200037a565b6200027761dead60016200037a565b60115460405190815233905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35062000704565b620002c48282620003ae565b5050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6008545f906200034090620003398469d3c21bcecceda1000000620003d8565b90620003ec565b92915050565b62000350620003f9565b6001600160a01b03919091165f908152601c60205260409020805460ff1916911515919091179055565b62000384620003f9565b6001600160a01b03919091165f908152601b60205260409020805460ff1916911515919091179055565b620003ba82826200045a565b5f828152600160205260409020620003d39082620004f8565b505050565b5f620003e58284620006c0565b9392505050565b5f620003e58284620006e4565b6007546001600160a01b03163314620004585760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640160405180910390fd5b565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16620002c4575f828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620004b43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f620003e5836001600160a01b0384165f8181526001830160205260408120546200054f57508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915562000340565b505f62000340565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200058057607f821691505b6020821081036200059f57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620003d357805f5260205f20601f840160051c81016020851015620005cc5750805b601f840160051c820191505b81811015620005ed575f8155600101620005d8565b5050505050565b81516001600160401b0381111562000610576200061062000557565b62000628816200062184546200056b565b84620005a5565b602080601f8311600181146200065e575f8415620006465750858301515b5f19600386901b1c1916600185901b178555620006b8565b5f85815260208120601f198616915b828110156200068e578886015182559484019460019091019084016200066d565b5085821015620006ac57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b80820281158282048414176200034057634e487b7160e01b5f52601160045260245ffd5b5f82620006ff57634e487b7160e01b5f52601260045260245ffd5b500490565b612cbe80620007125f395ff3fe608060405234801561000f575f80fd5b50600436106103eb575f3560e01c806379cc67901161020b578063ac3cdc001161011f578063d505accf116100b4578063e1bc339411610084578063e1bc3394146108bf578063e6be4a72146108e1578063ec342ad0146108f4578063f2fde38b14610903578063f8b45b0514610916575f80fd5b8063d505accf1461084d578063d539139314610860578063d547741f14610874578063dd62ed3e14610887575f80fd5b8063c0246668116100ef578063c024666814610815578063c3f70b5214610828578063ca15c87314610831578063d3288e5a14610844575f80fd5b8063ac3cdc00146107c5578063ad381a00146107ce578063b62496f5146107e1578063bbc0c74214610803575f80fd5b8063917505f4116101a057806397d63f931161017057806397d63f931461077c5780639a7a23d614610785578063a217fddf14610798578063a457c2d71461079f578063a9059cbb146107b2575f80fd5b8063917505f41461073b57806391c01c2b1461074e57806391d148541461076157806395d89b4114610774575f80fd5b806383eb70e5116101db57806383eb70e5146106e85780638a8c523c1461070f5780638da5cb5b146107175780639010d07c14610728575f80fd5b806379cc6790146106905780637af548c1146106a35780637ecebe00146106b65780637f51bb1f146106d5575f80fd5b8063313ce567116103025780634a62bb651161029757806370a082311161026757806370a0823114610651578063715018a614610664578063751039fc1461066c5780637571336a1461067457806378b8071a14610687575f80fd5b80634a62bb651461061757806361d027b31461062457806364dd48f514610637578063707d1ce914610648575f80fd5b806339509351116102d257806339509351146105b65780633af9e669146105c957806340c10f19146105f157806342966c6814610604575f80fd5b8063313ce56714610578578063336d2692146105875780633644e5151461059a57806336568abe146105a3575f80fd5b806320606b70116103835780632620b4ee116103535780632620b4ee146105155780632ded0b041461051e5780632f2ff15d1461052b5780632f34d2821461053e57806330adf81f14610551575f80fd5b806320606b70146104a657806323b872dd146104cd578063240f4e53146104e0578063248a9ca3146104f3575f80fd5b80630d64f1b6116103be5780630d64f1b61461045657806311d3e6c41461046b57806318160ddd146104735780631f7701db1461047b575f80fd5b806301ffc9a7146103ef57806306b993fd1461041757806306fdde031461042e578063095ea7b314610443575b5f80fd5b6104026103fd3660046127d6565b61091f565b60405190151581526020015b60405180910390f35b61042060085481565b60405190815260200161040e565b610436610949565b60405161040e919061281f565b610402610451366004612865565b6109d9565b610469610464366004612865565b610a31565b005b610420610a7b565b601254610420565b600b5461048e906001600160a01b031681565b6040516001600160a01b03909116815260200161040e565b6104207f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6104026104db36600461288f565b610a89565b6104206104ee3660046128cd565b610bb4565b6104206105013660046128cd565b5f9081526020819052604090206001015490565b61042060195481565b6013546104029060ff1681565b6104696105393660046128e4565b610bbe565b61046961054c366004612912565b610be7565b6104207f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6040516012815260200161040e565b610402610595366004612865565b610c11565b610420600f5481565b6104696105b13660046128e4565b610ccc565b6104026105c4366004612865565b610d46565b6104206105d7366004612912565b6001600160a01b03165f9081526009602052604090205490565b6104026105ff366004612865565b610db6565b6104696106123660046128cd565b610dfd565b601a546104029060ff1681565b600e5461048e906001600160a01b031681565b61042069d3c21bcecceda100000081565b61042060185481565b61042061065f366004612912565b610e09565b610469610e2a565b610469610e3d565b61046961068236600461293a565b610e51565b61042060165481565b61046961069e366004612865565b610e83565b6104206106b1366004612966565b610e98565b6104206106c4366004612912565b60106020525f908152604090205481565b6104696106e3366004612912565b6110ab565b6104207f5fde63b561377d1441afa201ff619faac2ff8fed70a7fbdbe7a5cb07768c0b7581565b6104696110d5565b6007546001600160a01b031661048e565b61048e61073636600461299c565b611137565b610402610749366004612865565b61114e565b61046961075c3660046128cd565b61118c565b61040261076f3660046128e4565b6111a6565b6104366111ce565b610420600c5481565b61046961079336600461293a565b6111dd565b6104205f81565b6104026107ad366004612865565b61120f565b6104026107c0366004612865565b6112d2565b610420600d5481565b6104206107dc3660046128cd565b6112e9565b6104026107ef366004612912565b601d6020525f908152604090205460ff1681565b601a5461040290610100900460ff1681565b61046961082336600461293a565b6112f3565b61042060145481565b61042061083f3660046128cd565b611325565b61042060175481565b61046961085b3660046129bc565b61133b565b6104205f80516020612c2983398151915281565b6104696108823660046128e4565b6115b4565b610420610895366004612a2d565b6001600160a01b039182165f908152600a6020908152604080832093909416825291909152205490565b6104026108cd366004612912565b601c6020525f908152604090205460ff1681565b6104696108ef366004612865565b6115d8565b610420670de0b6b3a764000081565b610469610911366004612912565b61169b565b61042060155481565b5f6001600160e01b03198216635a05180f60e01b1480610943575061094382611711565b92915050565b60606005805461095890612a59565b80601f016020809104026020016040519081016040528092919081815260200182805461098490612a59565b80156109cf5780601f106109a6576101008083540402835291602001916109cf565b820191905f5260205f20905b8154815290600101906020018083116109b257829003601f168201915b5050505050905090565b335f818152600a602090815260408083206001600160a01b038716808552925280832085905551919290915f80516020612c6983398151915290610a209086815260200190565b60405180910390a350600192915050565b610a485f80516020612c29833981519152336111a6565b610a6d5760405162461bcd60e51b8152600401610a6490612a91565b60405180910390fd5b610a778282611745565b5050565b5f610a846117d3565b905090565b5f826001600160a01b038116610a9d575f80fd5b306001600160a01b03821603610ab1575f80fd5b6001600160a01b0385165f908152600a60209081526040808320338452909152902054610ade90846117e3565b6001600160a01b0386165f908152600a60209081526040808320338452909152812091909155610b0d846117ee565b6001600160a01b0387165f90815260096020526040902054909150610b3290826117e3565b6001600160a01b038088165f908152600960205260408082209390935590871681522054610b60908261180b565b6001600160a01b038087165f8181526009602052604090819020939093559151908816905f80516020612c4983398151915290610ba09088815260200190565b60405180910390a350600195945050505050565b5f61094382611816565b5f82815260208190526040902060010154610bd88161183a565b610be28383611844565b505050565b610bef611865565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b5f826001600160a01b038116610c25575f80fd5b306001600160a01b03821603610c39575f80fd5b335f90815260096020526040902054610c5290846117e3565b335f90815260096020526040808220929092556001600160a01b03861681522054610c7d908461180b565b6001600160a01b0385165f81815260096020526040902091909155335f80516020612c49833981519152610cb086611816565b6040519081526020015b60405180910390a35060019392505050565b6001600160a01b0381163314610d3c5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610a64565b610a7782826118bf565b335f908152600a602090815260408083206001600160a01b0386168452909152812054610d73908361180b565b335f818152600a602090815260408083206001600160a01b038916808552908352928190208590555193845290925f80516020612c698339815191529101610a20565b5f610dce5f80516020612c29833981519152336111a6565b610dea5760405162461bcd60e51b8152600401610a6490612a91565b610df483836118e0565b50600192915050565b610e0681611a10565b50565b6001600160a01b0381165f9081526009602052604081205461094390611816565b610e32611865565b610e3b5f611aca565b565b610e45611865565b601a805460ff19169055565b610e59611865565b6001600160a01b03919091165f908152601c60205260409020805460ff1916911515919091179055565b610e8e823383611b1b565b610a778282611ba5565b5f610ec37f5fde63b561377d1441afa201ff619faac2ff8fed70a7fbdbe7a5cb07768c0b75336111a6565b610f085760405162461bcd60e51b81526020600482015260166024820152754d7573742068617665207265626173657220726f6c6560501b6044820152606401610a64565b825f03610f5e576008546040805186815260208101839052908101919091527fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c0906060015b60405180910390a1506012546110a4565b60085482610f9657610f8e670de0b6b3a7640000610f88610f7f82886117e3565b60085490611cc4565b90611ccf565b600855610fd9565b5f610fb0670de0b6b3a7640000610f88610f7f828961180b565b9050610fba6117d3565b811015610fcb576008819055610fd7565b610fd36117d3565b6008555b505b610fe4600c54611816565b601255600b546001600160a01b03161561105b57600b5f9054906101000a90046001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611044575f80fd5b505af1158015611056573d5f803e3d5ffd5b505050505b600854604080518781526020810184905280820192909252517fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c09181900360600190a150506012545b9392505050565b6110b3611865565b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6110dd611865565b601a54610100900460ff16156111265760405162461bcd60e51b815260206004820152600e60248201526d151bdad95b881b185d5b98da195960921b6044820152606401610a64565b601a805461ff001916610100179055565b5f8281526001602052604081206110a49083611cda565b5f6111665f80516020612c29833981519152336111a6565b6111825760405162461bcd60e51b8152600401610a6490612a91565b610df48383611ce5565b611194611865565b60648111156111a1575f80fd5b600d55565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461095890612a59565b6111e5611865565b6001600160a01b03919091165f908152601d60205260409020805460ff1916911515919091179055565b335f908152600a602090815260408083206001600160a01b038616845290915281205480831061126157335f908152600a602090815260408083206001600160a01b038816845290915281205561128f565b61126b81846117e3565b335f908152600a602090815260408083206001600160a01b03891684529091529020555b335f818152600a602090815260408083206001600160a01b038916808552908352928190205490519081529192915f80516020612c698339815191529101610cba565b5f336112df818585611e0c565b5060019392505050565b5f610943826117ee565b6112fb611865565b6001600160a01b03919091165f908152601b60205260409020805460ff1916911515919091179055565b5f81815260016020526040812061094390612216565b834211156113805760405162461bcd60e51b8152602060048201526012602482015271189d18cbdc195c9b5a5d0b595e1c1a5c995960721b6044820152606401610a64565b600f546001600160a01b0388165f90815260106020526040812080549192917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b9190876113d283612ad4565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e0016040516020818303038152906040528051906020012060405160200161144b92919061190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209091012090506001600160a01b0388166114b35760405162461bcd60e51b815260206004820152601560248201527406274632f696e76616c69642d616464726573732d3605c1b6044820152606401610a64565b604080515f81526020810180835283905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa158015611503573d5f803e3d5ffd5b505050602060405103516001600160a01b0316886001600160a01b0316146115625760405162461bcd60e51b8152602060048201526012602482015271189d18cbda5b9d985b1a590b5c195c9b5a5d60721b6044820152606401610a64565b6001600160a01b038881165f818152600a60209081526040808320948c16808452948252918290208a905590518981525f80516020612c69833981519152910160405180910390a35050505050505050565b5f828152602081905260409020600101546115ce8161183a565b610be283836118bf565b6115e0611865565b60135460405163a9059cbb60e01b81526001600160a01b0361010090920482166004820152602481018390525f9184169063a9059cbb906044016020604051808303815f875af1158015611636573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165a9190612aec565b905080610be25760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610a64565b6116a3611865565b6001600160a01b0381166117085760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a64565b610e0681611aca565b5f6001600160e01b03198216637965db0b60e01b148061094357506301ffc9a760e01b6001600160e01b0319831614610943565b61175c5f80516020612c29833981519152336111a6565b6117785760405162461bcd60e51b8152600401610a6490612a91565b5f61178260125490565b61178d906064612b07565b600d546117a284670de0b6b3a7640000612b07565b6117ac9190612b07565b6117b69190612b1e565b90506117c283836118e0565b6117cd5f825f61221f565b50505050565b5f600c545f19610a849190612b1e565b5f6110a48284612b3d565b6008545f9061094390610f888469d3c21bcecceda1000000611cc4565b5f6110a48284612b50565b5f61094369d3c21bcecceda1000000610f8860085485611cc490919063ffffffff16565b610e068133612269565b61184e82826122c2565b5f828152600160205260409020610be29082612345565b6007546001600160a01b03163314610e3b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a64565b6118c98282612359565b5f828152600160205260409020610be290826123bd565b6012546118ed908261180b565b6012555f6118fa826117ee565b600c5490915061190a908261180b565b600c556119156117d3565b60085411156119665760405162461bcd60e51b815260206004820152601a60248201527f6d6178207363616c696e6720666163746f7220746f6f206c6f770000000000006044820152606401610a64565b6001600160a01b0383165f90815260096020526040902054611988908261180b565b6001600160a01b0384165f818152600960209081526040918290209390935580519182529181018490527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885910160405180910390a16040518281526001600160a01b038416905f905f80516020612c49833981519152906020015b60405180910390a3505050565b601254611a1d90826117e3565b6012555f611a2a826117ee565b600c54909150611a3a90826117e3565b600c55335f90815260096020526040902054611a5690826117e3565b335f818152600960209081526040918290209390935580519182529181018490527fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5910160405180910390a16040518281525f9033905f80516020612c498339815191529060200160405180910390a35050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b038381165f908152600a60209081526040808320938616835292905220545f1981146117cd5781811015611b985760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a64565b6117cd84848484036123d1565b6001600160a01b038216611c055760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a64565b6001600160a01b0382165f9081526002602052604090205481811015611c785760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a64565b6001600160a01b0383165f8181526002602090815260408083208686039055600480548790039055518581529192915f80516020612c49833981519152910160405180910390a3505050565b5f6110a48284612b07565b5f6110a48284612b1e565b5f6110a483836124d9565b600c54611cf2908261180b565b600c555f611cff82611816565b601254909150611d0f908261180b565b601255611d1a6117d3565b6008541115611d6b5760405162461bcd60e51b815260206004820152601a60248201527f6d6178207363616c696e6720666163746f7220746f6f206c6f770000000000006044820152606401610a64565b6001600160a01b0383165f90815260096020526040902054611d8d908361180b565b6001600160a01b0384165f818152600960209081526040918290209390935580519182529181018390527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885910160405180910390a16040518181526001600160a01b038416905f905f80516020612c4983398151915290602001611a03565b816001600160a01b038116611e1f575f80fd5b306001600160a01b03821603611e33575f80fd5b5f611e3d836117ee565b601a5490915060ff1615612177576007546001600160a01b03868116911614801590611e7757506007546001600160a01b03858116911614155b8015611e8e57506001600160a01b03841661dead14155b1561217757601a54610100900460ff16611f24576001600160a01b0385165f908152601b602052604090205460ff1680611edf57506001600160a01b0384165f908152601b602052604090205460ff165b611f245760405162461bcd60e51b81526020600482015260166024820152752a3930b234b7339034b9903737ba1030b1ba34bb329760511b6044820152606401610a64565b6001600160a01b0385165f908152601d602052604090205460ff168015611f6357506001600160a01b0384165f908152601c602052604090205460ff16155b1561204057601654811115611fd25760405162461bcd60e51b815260206004820152602f60248201527f427579207472616e7366657220616d6f756e742065786365656473207468652060448201526e36b0bc2a3930b739b0b1ba34b7b71760891b6064820152608401610a64565b6017546001600160a01b0385165f90815260096020526040902054611ff79083612b50565b111561203b5760405162461bcd60e51b815260206004820152601360248201527213585e081dd85b1b195d08195e18d959591959606a1b6044820152606401610a64565b612177565b6001600160a01b0384165f908152601d602052604090205460ff16801561207f57506001600160a01b0385165f908152601c602052604090205460ff16155b156120ef5760165481111561203b5760405162461bcd60e51b815260206004820152603060248201527f53656c6c207472616e7366657220616d6f756e7420657863656564732074686560448201526f1036b0bc2a3930b739b0b1ba34b7b71760811b6064820152608401610a64565b6001600160a01b0384165f908152601c602052604090205460ff16612177576017546001600160a01b0385165f908152600960205260409020546121339083612b50565b11156121775760405162461bcd60e51b815260206004820152601360248201527213585e081dd85b1b195d08195e18d959591959606a1b6044820152606401610a64565b6001600160a01b0385165f9081526009602052604090205461219990826117e3565b6001600160a01b038087165f9081526009602052604080822093909355908616815220546121c7908261180b565b6001600160a01b038086165f8181526009602052604090819020939093559151908716905f80516020612c49833981519152906122079087815260200190565b60405180910390a35050505050565b5f610943825490565b5f825f03610f5e576008546040805186815260208101839052908101919091527fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c090606001610f4d565b61227382826111a6565b610a7757612280816124ff565b61228b836020612511565b60405160200161229c929190612b63565b60408051601f198184030181529082905262461bcd60e51b8252610a649160040161281f565b6122cc82826111a6565b610a77575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556123013390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f6110a4836001600160a01b0384166126a7565b61236382826111a6565b15610a77575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f6110a4836001600160a01b0384166126f3565b6001600160a01b0383166124335760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a64565b6001600160a01b0382166124945760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a64565b6001600160a01b038381165f8181526003602090815260408083209487168084529482529182902085905590518481525f80516020612c698339815191529101611a03565b5f825f0182815481106124ee576124ee612bd7565b905f5260205f200154905092915050565b60606109436001600160a01b03831660145b60605f61251f836002612b07565b61252a906002612b50565b67ffffffffffffffff81111561254257612542612beb565b6040519080825280601f01601f19166020018201604052801561256c576020820181803683370190505b509050600360fc1b815f8151811061258657612586612bd7565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106125b4576125b4612bd7565b60200101906001600160f81b03191690815f1a9053505f6125d6846002612b07565b6125e1906001612b50565b90505b6001811115612658576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061261557612615612bd7565b1a60f81b82828151811061262b5761262b612bd7565b60200101906001600160f81b03191690815f1a90535060049490941c9361265181612bff565b90506125e4565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a64565b5f8181526001830160205260408120546126ec57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610943565b505f610943565b5f81815260018301602052604081205480156127cd575f612715600183612b3d565b85549091505f9061272890600190612b3d565b9050818114612787575f865f01828154811061274657612746612bd7565b905f5260205f200154905080875f01848154811061276657612766612bd7565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061279857612798612c14565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610943565b5f915050610943565b5f602082840312156127e6575f80fd5b81356001600160e01b0319811681146110a4575f80fd5b5f5b838110156128175781810151838201526020016127ff565b50505f910152565b602081525f825180602084015261283d8160408501602087016127fd565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610e06575f80fd5b5f8060408385031215612876575f80fd5b823561288181612851565b946020939093013593505050565b5f805f606084860312156128a1575f80fd5b83356128ac81612851565b925060208401356128bc81612851565b929592945050506040919091013590565b5f602082840312156128dd575f80fd5b5035919050565b5f80604083850312156128f5575f80fd5b82359150602083013561290781612851565b809150509250929050565b5f60208284031215612922575f80fd5b81356110a481612851565b8015158114610e06575f80fd5b5f806040838503121561294b575f80fd5b823561295681612851565b915060208301356129078161292d565b5f805f60608486031215612978575f80fd5b833592506020840135915060408401356129918161292d565b809150509250925092565b5f80604083850312156129ad575f80fd5b50508035926020909101359150565b5f805f805f805f60e0888a0312156129d2575f80fd5b87356129dd81612851565b965060208801356129ed81612851565b95506040880135945060608801359350608088013560ff81168114612a10575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215612a3e575f80fd5b8235612a4981612851565b9150602083013561290781612851565b600181811c90821680612a6d57607f821691505b602082108103612a8b57634e487b7160e01b5f52602260045260245ffd5b50919050565b6020808252601590820152744d7573742068617665206d696e74657220726f6c6560581b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612ae557612ae5612ac0565b5060010190565b5f60208284031215612afc575f80fd5b81516110a48161292d565b808202811582820484141761094357610943612ac0565b5f82612b3857634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561094357610943612ac0565b8082018082111561094357610943612ac0565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351612b9a8160178501602088016127fd565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612bcb8160288401602088016127fd565b01602801949350505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b5f81612c0d57612c0d612ac0565b505f190190565b634e487b7160e01b5f52603160045260245ffdfe9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220c3a0c3968ed5101c18217aa716b3d306d14c1b88d8249420bbace1c7ae48041864736f6c63430008170033

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106103eb575f3560e01c806379cc67901161020b578063ac3cdc001161011f578063d505accf116100b4578063e1bc339411610084578063e1bc3394146108bf578063e6be4a72146108e1578063ec342ad0146108f4578063f2fde38b14610903578063f8b45b0514610916575f80fd5b8063d505accf1461084d578063d539139314610860578063d547741f14610874578063dd62ed3e14610887575f80fd5b8063c0246668116100ef578063c024666814610815578063c3f70b5214610828578063ca15c87314610831578063d3288e5a14610844575f80fd5b8063ac3cdc00146107c5578063ad381a00146107ce578063b62496f5146107e1578063bbc0c74214610803575f80fd5b8063917505f4116101a057806397d63f931161017057806397d63f931461077c5780639a7a23d614610785578063a217fddf14610798578063a457c2d71461079f578063a9059cbb146107b2575f80fd5b8063917505f41461073b57806391c01c2b1461074e57806391d148541461076157806395d89b4114610774575f80fd5b806383eb70e5116101db57806383eb70e5146106e85780638a8c523c1461070f5780638da5cb5b146107175780639010d07c14610728575f80fd5b806379cc6790146106905780637af548c1146106a35780637ecebe00146106b65780637f51bb1f146106d5575f80fd5b8063313ce567116103025780634a62bb651161029757806370a082311161026757806370a0823114610651578063715018a614610664578063751039fc1461066c5780637571336a1461067457806378b8071a14610687575f80fd5b80634a62bb651461061757806361d027b31461062457806364dd48f514610637578063707d1ce914610648575f80fd5b806339509351116102d257806339509351146105b65780633af9e669146105c957806340c10f19146105f157806342966c6814610604575f80fd5b8063313ce56714610578578063336d2692146105875780633644e5151461059a57806336568abe146105a3575f80fd5b806320606b70116103835780632620b4ee116103535780632620b4ee146105155780632ded0b041461051e5780632f2ff15d1461052b5780632f34d2821461053e57806330adf81f14610551575f80fd5b806320606b70146104a657806323b872dd146104cd578063240f4e53146104e0578063248a9ca3146104f3575f80fd5b80630d64f1b6116103be5780630d64f1b61461045657806311d3e6c41461046b57806318160ddd146104735780631f7701db1461047b575f80fd5b806301ffc9a7146103ef57806306b993fd1461041757806306fdde031461042e578063095ea7b314610443575b5f80fd5b6104026103fd3660046127d6565b61091f565b60405190151581526020015b60405180910390f35b61042060085481565b60405190815260200161040e565b610436610949565b60405161040e919061281f565b610402610451366004612865565b6109d9565b610469610464366004612865565b610a31565b005b610420610a7b565b601254610420565b600b5461048e906001600160a01b031681565b6040516001600160a01b03909116815260200161040e565b6104207f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b6104026104db36600461288f565b610a89565b6104206104ee3660046128cd565b610bb4565b6104206105013660046128cd565b5f9081526020819052604090206001015490565b61042060195481565b6013546104029060ff1681565b6104696105393660046128e4565b610bbe565b61046961054c366004612912565b610be7565b6104207f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6040516012815260200161040e565b610402610595366004612865565b610c11565b610420600f5481565b6104696105b13660046128e4565b610ccc565b6104026105c4366004612865565b610d46565b6104206105d7366004612912565b6001600160a01b03165f9081526009602052604090205490565b6104026105ff366004612865565b610db6565b6104696106123660046128cd565b610dfd565b601a546104029060ff1681565b600e5461048e906001600160a01b031681565b61042069d3c21bcecceda100000081565b61042060185481565b61042061065f366004612912565b610e09565b610469610e2a565b610469610e3d565b61046961068236600461293a565b610e51565b61042060165481565b61046961069e366004612865565b610e83565b6104206106b1366004612966565b610e98565b6104206106c4366004612912565b60106020525f908152604090205481565b6104696106e3366004612912565b6110ab565b6104207f5fde63b561377d1441afa201ff619faac2ff8fed70a7fbdbe7a5cb07768c0b7581565b6104696110d5565b6007546001600160a01b031661048e565b61048e61073636600461299c565b611137565b610402610749366004612865565b61114e565b61046961075c3660046128cd565b61118c565b61040261076f3660046128e4565b6111a6565b6104366111ce565b610420600c5481565b61046961079336600461293a565b6111dd565b6104205f81565b6104026107ad366004612865565b61120f565b6104026107c0366004612865565b6112d2565b610420600d5481565b6104206107dc3660046128cd565b6112e9565b6104026107ef366004612912565b601d6020525f908152604090205460ff1681565b601a5461040290610100900460ff1681565b61046961082336600461293a565b6112f3565b61042060145481565b61042061083f3660046128cd565b611325565b61042060175481565b61046961085b3660046129bc565b61133b565b6104205f80516020612c2983398151915281565b6104696108823660046128e4565b6115b4565b610420610895366004612a2d565b6001600160a01b039182165f908152600a6020908152604080832093909416825291909152205490565b6104026108cd366004612912565b601c6020525f908152604090205460ff1681565b6104696108ef366004612865565b6115d8565b610420670de0b6b3a764000081565b610469610911366004612912565b61169b565b61042060155481565b5f6001600160e01b03198216635a05180f60e01b1480610943575061094382611711565b92915050565b60606005805461095890612a59565b80601f016020809104026020016040519081016040528092919081815260200182805461098490612a59565b80156109cf5780601f106109a6576101008083540402835291602001916109cf565b820191905f5260205f20905b8154815290600101906020018083116109b257829003601f168201915b5050505050905090565b335f818152600a602090815260408083206001600160a01b038716808552925280832085905551919290915f80516020612c6983398151915290610a209086815260200190565b60405180910390a350600192915050565b610a485f80516020612c29833981519152336111a6565b610a6d5760405162461bcd60e51b8152600401610a6490612a91565b60405180910390fd5b610a778282611745565b5050565b5f610a846117d3565b905090565b5f826001600160a01b038116610a9d575f80fd5b306001600160a01b03821603610ab1575f80fd5b6001600160a01b0385165f908152600a60209081526040808320338452909152902054610ade90846117e3565b6001600160a01b0386165f908152600a60209081526040808320338452909152812091909155610b0d846117ee565b6001600160a01b0387165f90815260096020526040902054909150610b3290826117e3565b6001600160a01b038088165f908152600960205260408082209390935590871681522054610b60908261180b565b6001600160a01b038087165f8181526009602052604090819020939093559151908816905f80516020612c4983398151915290610ba09088815260200190565b60405180910390a350600195945050505050565b5f61094382611816565b5f82815260208190526040902060010154610bd88161183a565b610be28383611844565b505050565b610bef611865565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b5f826001600160a01b038116610c25575f80fd5b306001600160a01b03821603610c39575f80fd5b335f90815260096020526040902054610c5290846117e3565b335f90815260096020526040808220929092556001600160a01b03861681522054610c7d908461180b565b6001600160a01b0385165f81815260096020526040902091909155335f80516020612c49833981519152610cb086611816565b6040519081526020015b60405180910390a35060019392505050565b6001600160a01b0381163314610d3c5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610a64565b610a7782826118bf565b335f908152600a602090815260408083206001600160a01b0386168452909152812054610d73908361180b565b335f818152600a602090815260408083206001600160a01b038916808552908352928190208590555193845290925f80516020612c698339815191529101610a20565b5f610dce5f80516020612c29833981519152336111a6565b610dea5760405162461bcd60e51b8152600401610a6490612a91565b610df483836118e0565b50600192915050565b610e0681611a10565b50565b6001600160a01b0381165f9081526009602052604081205461094390611816565b610e32611865565b610e3b5f611aca565b565b610e45611865565b601a805460ff19169055565b610e59611865565b6001600160a01b03919091165f908152601c60205260409020805460ff1916911515919091179055565b610e8e823383611b1b565b610a778282611ba5565b5f610ec37f5fde63b561377d1441afa201ff619faac2ff8fed70a7fbdbe7a5cb07768c0b75336111a6565b610f085760405162461bcd60e51b81526020600482015260166024820152754d7573742068617665207265626173657220726f6c6560501b6044820152606401610a64565b825f03610f5e576008546040805186815260208101839052908101919091527fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c0906060015b60405180910390a1506012546110a4565b60085482610f9657610f8e670de0b6b3a7640000610f88610f7f82886117e3565b60085490611cc4565b90611ccf565b600855610fd9565b5f610fb0670de0b6b3a7640000610f88610f7f828961180b565b9050610fba6117d3565b811015610fcb576008819055610fd7565b610fd36117d3565b6008555b505b610fe4600c54611816565b601255600b546001600160a01b03161561105b57600b5f9054906101000a90046001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611044575f80fd5b505af1158015611056573d5f803e3d5ffd5b505050505b600854604080518781526020810184905280820192909252517fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c09181900360600190a150506012545b9392505050565b6110b3611865565b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6110dd611865565b601a54610100900460ff16156111265760405162461bcd60e51b815260206004820152600e60248201526d151bdad95b881b185d5b98da195960921b6044820152606401610a64565b601a805461ff001916610100179055565b5f8281526001602052604081206110a49083611cda565b5f6111665f80516020612c29833981519152336111a6565b6111825760405162461bcd60e51b8152600401610a6490612a91565b610df48383611ce5565b611194611865565b60648111156111a1575f80fd5b600d55565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606006805461095890612a59565b6111e5611865565b6001600160a01b03919091165f908152601d60205260409020805460ff1916911515919091179055565b335f908152600a602090815260408083206001600160a01b038616845290915281205480831061126157335f908152600a602090815260408083206001600160a01b038816845290915281205561128f565b61126b81846117e3565b335f908152600a602090815260408083206001600160a01b03891684529091529020555b335f818152600a602090815260408083206001600160a01b038916808552908352928190205490519081529192915f80516020612c698339815191529101610cba565b5f336112df818585611e0c565b5060019392505050565b5f610943826117ee565b6112fb611865565b6001600160a01b03919091165f908152601b60205260409020805460ff1916911515919091179055565b5f81815260016020526040812061094390612216565b834211156113805760405162461bcd60e51b8152602060048201526012602482015271189d18cbdc195c9b5a5d0b595e1c1a5c995960721b6044820152606401610a64565b600f546001600160a01b0388165f90815260106020526040812080549192917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918b918b918b9190876113d283612ad4565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810187905260e0016040516020818303038152906040528051906020012060405160200161144b92919061190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209091012090506001600160a01b0388166114b35760405162461bcd60e51b815260206004820152601560248201527406274632f696e76616c69642d616464726573732d3605c1b6044820152606401610a64565b604080515f81526020810180835283905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa158015611503573d5f803e3d5ffd5b505050602060405103516001600160a01b0316886001600160a01b0316146115625760405162461bcd60e51b8152602060048201526012602482015271189d18cbda5b9d985b1a590b5c195c9b5a5d60721b6044820152606401610a64565b6001600160a01b038881165f818152600a60209081526040808320948c16808452948252918290208a905590518981525f80516020612c69833981519152910160405180910390a35050505050505050565b5f828152602081905260409020600101546115ce8161183a565b610be283836118bf565b6115e0611865565b60135460405163a9059cbb60e01b81526001600160a01b0361010090920482166004820152602481018390525f9184169063a9059cbb906044016020604051808303815f875af1158015611636573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165a9190612aec565b905080610be25760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610a64565b6116a3611865565b6001600160a01b0381166117085760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610a64565b610e0681611aca565b5f6001600160e01b03198216637965db0b60e01b148061094357506301ffc9a760e01b6001600160e01b0319831614610943565b61175c5f80516020612c29833981519152336111a6565b6117785760405162461bcd60e51b8152600401610a6490612a91565b5f61178260125490565b61178d906064612b07565b600d546117a284670de0b6b3a7640000612b07565b6117ac9190612b07565b6117b69190612b1e565b90506117c283836118e0565b6117cd5f825f61221f565b50505050565b5f600c545f19610a849190612b1e565b5f6110a48284612b3d565b6008545f9061094390610f888469d3c21bcecceda1000000611cc4565b5f6110a48284612b50565b5f61094369d3c21bcecceda1000000610f8860085485611cc490919063ffffffff16565b610e068133612269565b61184e82826122c2565b5f828152600160205260409020610be29082612345565b6007546001600160a01b03163314610e3b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a64565b6118c98282612359565b5f828152600160205260409020610be290826123bd565b6012546118ed908261180b565b6012555f6118fa826117ee565b600c5490915061190a908261180b565b600c556119156117d3565b60085411156119665760405162461bcd60e51b815260206004820152601a60248201527f6d6178207363616c696e6720666163746f7220746f6f206c6f770000000000006044820152606401610a64565b6001600160a01b0383165f90815260096020526040902054611988908261180b565b6001600160a01b0384165f818152600960209081526040918290209390935580519182529181018490527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885910160405180910390a16040518281526001600160a01b038416905f905f80516020612c49833981519152906020015b60405180910390a3505050565b601254611a1d90826117e3565b6012555f611a2a826117ee565b600c54909150611a3a90826117e3565b600c55335f90815260096020526040902054611a5690826117e3565b335f818152600960209081526040918290209390935580519182529181018490527fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5910160405180910390a16040518281525f9033905f80516020612c498339815191529060200160405180910390a35050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b038381165f908152600a60209081526040808320938616835292905220545f1981146117cd5781811015611b985760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a64565b6117cd84848484036123d1565b6001600160a01b038216611c055760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a64565b6001600160a01b0382165f9081526002602052604090205481811015611c785760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a64565b6001600160a01b0383165f8181526002602090815260408083208686039055600480548790039055518581529192915f80516020612c49833981519152910160405180910390a3505050565b5f6110a48284612b07565b5f6110a48284612b1e565b5f6110a483836124d9565b600c54611cf2908261180b565b600c555f611cff82611816565b601254909150611d0f908261180b565b601255611d1a6117d3565b6008541115611d6b5760405162461bcd60e51b815260206004820152601a60248201527f6d6178207363616c696e6720666163746f7220746f6f206c6f770000000000006044820152606401610a64565b6001600160a01b0383165f90815260096020526040902054611d8d908361180b565b6001600160a01b0384165f818152600960209081526040918290209390935580519182529181018390527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885910160405180910390a16040518181526001600160a01b038416905f905f80516020612c4983398151915290602001611a03565b816001600160a01b038116611e1f575f80fd5b306001600160a01b03821603611e33575f80fd5b5f611e3d836117ee565b601a5490915060ff1615612177576007546001600160a01b03868116911614801590611e7757506007546001600160a01b03858116911614155b8015611e8e57506001600160a01b03841661dead14155b1561217757601a54610100900460ff16611f24576001600160a01b0385165f908152601b602052604090205460ff1680611edf57506001600160a01b0384165f908152601b602052604090205460ff165b611f245760405162461bcd60e51b81526020600482015260166024820152752a3930b234b7339034b9903737ba1030b1ba34bb329760511b6044820152606401610a64565b6001600160a01b0385165f908152601d602052604090205460ff168015611f6357506001600160a01b0384165f908152601c602052604090205460ff16155b1561204057601654811115611fd25760405162461bcd60e51b815260206004820152602f60248201527f427579207472616e7366657220616d6f756e742065786365656473207468652060448201526e36b0bc2a3930b739b0b1ba34b7b71760891b6064820152608401610a64565b6017546001600160a01b0385165f90815260096020526040902054611ff79083612b50565b111561203b5760405162461bcd60e51b815260206004820152601360248201527213585e081dd85b1b195d08195e18d959591959606a1b6044820152606401610a64565b612177565b6001600160a01b0384165f908152601d602052604090205460ff16801561207f57506001600160a01b0385165f908152601c602052604090205460ff16155b156120ef5760165481111561203b5760405162461bcd60e51b815260206004820152603060248201527f53656c6c207472616e7366657220616d6f756e7420657863656564732074686560448201526f1036b0bc2a3930b739b0b1ba34b7b71760811b6064820152608401610a64565b6001600160a01b0384165f908152601c602052604090205460ff16612177576017546001600160a01b0385165f908152600960205260409020546121339083612b50565b11156121775760405162461bcd60e51b815260206004820152601360248201527213585e081dd85b1b195d08195e18d959591959606a1b6044820152606401610a64565b6001600160a01b0385165f9081526009602052604090205461219990826117e3565b6001600160a01b038087165f9081526009602052604080822093909355908616815220546121c7908261180b565b6001600160a01b038086165f8181526009602052604090819020939093559151908716905f80516020612c49833981519152906122079087815260200190565b60405180910390a35050505050565b5f610943825490565b5f825f03610f5e576008546040805186815260208101839052908101919091527fc6642d24d84e7f3d36ca39f5cce10e75639d9b158d5193aa350e2f900653e4c090606001610f4d565b61227382826111a6565b610a7757612280816124ff565b61228b836020612511565b60405160200161229c929190612b63565b60408051601f198184030181529082905262461bcd60e51b8252610a649160040161281f565b6122cc82826111a6565b610a77575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556123013390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f6110a4836001600160a01b0384166126a7565b61236382826111a6565b15610a77575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f6110a4836001600160a01b0384166126f3565b6001600160a01b0383166124335760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a64565b6001600160a01b0382166124945760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a64565b6001600160a01b038381165f8181526003602090815260408083209487168084529482529182902085905590518481525f80516020612c698339815191529101611a03565b5f825f0182815481106124ee576124ee612bd7565b905f5260205f200154905092915050565b60606109436001600160a01b03831660145b60605f61251f836002612b07565b61252a906002612b50565b67ffffffffffffffff81111561254257612542612beb565b6040519080825280601f01601f19166020018201604052801561256c576020820181803683370190505b509050600360fc1b815f8151811061258657612586612bd7565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106125b4576125b4612bd7565b60200101906001600160f81b03191690815f1a9053505f6125d6846002612b07565b6125e1906001612b50565b90505b6001811115612658576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061261557612615612bd7565b1a60f81b82828151811061262b5761262b612bd7565b60200101906001600160f81b03191690815f1a90535060049490941c9361265181612bff565b90506125e4565b5083156110a45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a64565b5f8181526001830160205260408120546126ec57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610943565b505f610943565b5f81815260018301602052604081205480156127cd575f612715600183612b3d565b85549091505f9061272890600190612b3d565b9050818114612787575f865f01828154811061274657612746612bd7565b905f5260205f200154905080875f01848154811061276657612766612bd7565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061279857612798612c14565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610943565b5f915050610943565b5f602082840312156127e6575f80fd5b81356001600160e01b0319811681146110a4575f80fd5b5f5b838110156128175781810151838201526020016127ff565b50505f910152565b602081525f825180602084015261283d8160408501602087016127fd565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610e06575f80fd5b5f8060408385031215612876575f80fd5b823561288181612851565b946020939093013593505050565b5f805f606084860312156128a1575f80fd5b83356128ac81612851565b925060208401356128bc81612851565b929592945050506040919091013590565b5f602082840312156128dd575f80fd5b5035919050565b5f80604083850312156128f5575f80fd5b82359150602083013561290781612851565b809150509250929050565b5f60208284031215612922575f80fd5b81356110a481612851565b8015158114610e06575f80fd5b5f806040838503121561294b575f80fd5b823561295681612851565b915060208301356129078161292d565b5f805f60608486031215612978575f80fd5b833592506020840135915060408401356129918161292d565b809150509250925092565b5f80604083850312156129ad575f80fd5b50508035926020909101359150565b5f805f805f805f60e0888a0312156129d2575f80fd5b87356129dd81612851565b965060208801356129ed81612851565b95506040880135945060608801359350608088013560ff81168114612a10575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f8060408385031215612a3e575f80fd5b8235612a4981612851565b9150602083013561290781612851565b600181811c90821680612a6d57607f821691505b602082108103612a8b57634e487b7160e01b5f52602260045260245ffd5b50919050565b6020808252601590820152744d7573742068617665206d696e74657220726f6c6560581b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612ae557612ae5612ac0565b5060010190565b5f60208284031215612afc575f80fd5b81516110a48161292d565b808202811582820484141761094357610943612ac0565b5f82612b3857634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561094357610943612ac0565b8082018082111561094357610943612ac0565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351612b9a8160178501602088016127fd565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612bcb8160288401602088016127fd565b01602801949350505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b5f81612c0d57612c0d612ac0565b505f190190565b634e487b7160e01b5f52603160045260245ffdfe9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220c3a0c3968ed5101c18217aa716b3d306d14c1b88d8249420bbace1c7ae48041864736f6c63430008170033

Deployed Bytecode Sourcemap

70145:19694:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41414:290;;;;;;:::i;:::-;;:::i;:::-;;;470:14:1;;463:22;445:41;;433:2;418:18;41414:290:0;;;;;;;;70700:32;;;;;;;;;643:25:1;;;631:2;616:18;70700:32:0;497:177:1;47809:100:0;;;:::i;:::-;;;;;;;:::i;81849:251::-;;;;;;:::i;:::-;;:::i;87858:204::-;;;;;;:::i;:::-;;:::i;:::-;;73655:105;;;:::i;73395:100::-;73475:12;;73395:100;;70881:17;;;;;-1:-1:-1;;;;;70881:17:0;;;;;;-1:-1:-1;;;;;1967:32:1;;;1949:51;;1937:2;1922:18;70881:17:0;1791:215:1;71402:155:0;;71453:104;71402:155;;79551:605;;;;;;:::i;:::-;;:::i;88334:113::-;;;;;;:::i;:::-;;:::i;24483:181::-;;;;;;:::i;:::-;24602:7;24634:12;;;;;;;;;;:22;;;;24483:181;72061:39;;;;;;71800:25;;;;;;;;;24974:188;;;;;;:::i;:::-;;:::i;73503:70::-;;;;;;:::i;:::-;;:::i;71124:117::-;;71175:66;71124:117;;48771:93;;;48854:2;3750:36:1;;3738:2;3723:18;48771:93:0;3608:184:1;77127:431:0;;;;;;:::i;:::-;;:::i;71248:31::-;;;;;;26200:287;;;;;;:::i;:::-;;:::i;82473:422::-;;;;;;:::i;:::-;;:::i;80593:115::-;;;;;;:::i;:::-;-1:-1:-1;;;;;80683:17:0;80656:7;80683:17;;;:12;:17;;;;;;;80593:115;74198:205;;;;;;:::i;:::-;;:::i;75226:78::-;;;;;;:::i;:::-;;:::i;72115:33::-;;;;;;;;;70976:36;;;;;-1:-1:-1;;;;;70976:36:0;;;70454:49;;70497:6;70454:49;;72003:43;;;;;;80277:130;;;;;;:::i;:::-;;:::i;62060:103::-;;;:::i;88886:84::-;;;:::i;88978:138::-;;;;;;:::i;:::-;;:::i;71926:33::-;;;;;;60010:164;;;;;;:::i;:::-;;:::i;84810:1402::-;;;;;;:::i;:::-;;:::i;71288:41::-;;;;;;:::i;:::-;;;;;;;;;;;;;;88220:104;;;;;;:::i;:::-;;:::i;60440:64::-;;60479:25;60440:64;;89264:135;;;:::i;61412:87::-;61485:6;;-1:-1:-1;;;;;61485:6:0;61412:87;;42303:203;;;;;;:::i;:::-;;:::i;75956:223::-;;;;;;:::i;:::-;;:::i;88070:142::-;;;;;;:::i;:::-;;:::i;22906:197::-;;;;;;:::i;:::-;;:::i;48028:104::-;;;:::i;70905:25::-;;;;;;89407:138;;;;;;:::i;:::-;;:::i;21935:49::-;;21980:4;21935:49;;83157:612;;;;;;:::i;:::-;;:::i;49483:234::-;;;;;;:::i;:::-;;:::i;70937:32::-;;;;;;88455:115;;;;;;:::i;:::-;;:::i;72320:57::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;72155:33;;;;;;;;;;;;89124:132;;;;;;:::i;:::-;;:::i;71857:29::-;;;;;;42680:192;;;;;;:::i;:::-;;:::i;71966:28::-;;;;;;83814:988;;;;;;:::i;:::-;;:::i;60371:62::-;;-1:-1:-1;;;;;;;;;;;60371:62:0;;25455:190;;;;;;:::i;:::-;;:::i;81015:192::-;;;;;;:::i;:::-;-1:-1:-1;;;;;81165:25:0;;;81133:7;81165:25;;;:17;:25;;;;;;;;:34;;;;;;;;;;;;;81015:192;72256:57;;;;;;:::i;:::-;;;;;;;;;;;;;;;;89622:212;;;;;;:::i;:::-;;:::i;70572:37::-;;70603:6;70572:37;;62318:238;;;;;;:::i;:::-;;:::i;71893:24::-;;;;;;41414:290;41544:4;-1:-1:-1;;;;;;41586:57:0;;-1:-1:-1;;;41586:57:0;;:110;;;41660:36;41684:11;41660:23;:36::i;:::-;41566:130;41414:290;-1:-1:-1;;41414:290:0:o;47809:100::-;47863:13;47896:5;47889:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47809:100;:::o;81849:251::-;81990:10;81950:4;81972:29;;;:17;:29;;;;;;;;-1:-1:-1;;;;;81972:38:0;;;;;;;;;;:46;;;82034:36;81950:4;;81972:38;;-1:-1:-1;;;;;;;;;;;82034:36:0;;;82013:5;643:25:1;;631:2;616:18;;497:177;82034:36:0;;;;;;;;-1:-1:-1;82088:4:0;81849:251;;;;:::o;87858:204::-;87946:34;-1:-1:-1;;;;;;;;;;;174:10:0;22906:197;:::i;87946:34::-;87938:68;;;;-1:-1:-1;;;87938:68:0;;;;;;;:::i;:::-;;;;;;;;;88017:37;88037:8;88047:6;88017:19;:37::i;:::-;87858:204;;:::o;73655:105::-;73706:7;73733:19;:17;:19::i;:::-;73726:26;;73655:105;:::o;79551:605::-;79692:4;79679:2;-1:-1:-1;;;;;71714:18:0;;71706:27;;;;;;71766:4;-1:-1:-1;;;;;71752:19:0;;;71744:28;;;;;;-1:-1:-1;;;;;79778:23:0;::::1;;::::0;;;:17:::1;:23;::::0;;;;;;;79816:10:::1;79778:59:::0;;;;;;;;:70:::1;::::0;79842:5;79778:63:::1;:70::i;:::-;-1:-1:-1::0;;;;;79740:23:0;::::1;;::::0;;;:17:::1;:23;::::0;;;;;;;79764:10:::1;79740:35:::0;;;;;;;:108;;;;79910:21:::1;79925:5:::0;79910:14:::1;:21::i;:::-;-1:-1:-1::0;;;;;79991:18:0;::::1;;::::0;;;:12:::1;:18;::::0;;;;;79891:40;;-1:-1:-1;79991:32:0::1;::::0;79891:40;79991:22:::1;:32::i;:::-;-1:-1:-1::0;;;;;79970:18:0;;::::1;;::::0;;;:12:::1;:18;::::0;;;;;:53;;;;80053:16;;::::1;::::0;;;;:30:::1;::::0;80074:8;80053:20:::1;:30::i;:::-;-1:-1:-1::0;;;;;80034:16:0;;::::1;;::::0;;;:12:::1;:16;::::0;;;;;;:49;;;;80099:25;;;;::::1;::::0;-1:-1:-1;;;;;;;;;;;80099:25:0;::::1;::::0;80118:5;643:25:1;;631:2;616:18;;497:177;80099:25:0::1;;;;;;;;-1:-1:-1::0;80144:4:0::1;::::0;79551:605;-1:-1:-1;;;;;79551:605:0:o;88334:113::-;88392:7;88419:20;88434:4;88419:14;:20::i;24974:188::-;24602:7;24634:12;;;;;;;;;;:22;;;22426:16;22437:4;22426:10;:16::i;:::-;25129:25:::1;25140:4;25146:7;25129:10;:25::i;:::-;24974:188:::0;;;:::o;73503:70::-;61298:13;:11;:13::i;:::-;73554:6:::1;:11:::0;;-1:-1:-1;;;;;;73554:11:0::1;-1:-1:-1::0;;;;;73554:11:0;;;::::1;::::0;;;::::1;::::0;;73503:70::o;77127:431::-;77244:4;77222:2;-1:-1:-1;;;;;71714:18:0;;71706:27;;;;;;71766:4;-1:-1:-1;;;;;71752:19:0;;;71744:28;;;;;;77345:10:::1;77332:24;::::0;;;:12:::1;:24;::::0;;;;;:35:::1;::::0;77361:5;77332:28:::1;:35::i;:::-;77318:10;77305:24;::::0;;;:12:::1;:24;::::0;;;;;:62;;;;-1:-1:-1;;;;;77438:16:0;::::1;::::0;;;;:27:::1;::::0;77459:5;77438:20:::1;:27::i;:::-;-1:-1:-1::0;;;;;77419:16:0;::::1;;::::0;;;:12:::1;:16;::::0;;;;:46;;;;77490:10:::1;-1:-1:-1::0;;;;;;;;;;;77506:21:0::1;77521:5:::0;77506:14:::1;:21::i;:::-;77481:47;::::0;643:25:1;;;631:2;616:18;77481:47:0::1;;;;;;;;-1:-1:-1::0;77546:4:0::1;::::0;77127:431;-1:-1:-1;;;77127:431:0:o;26200:287::-;-1:-1:-1;;;;;26342:23:0;;174:10;26342:23;26320:120;;;;-1:-1:-1;;;26320:120:0;;7566:2:1;26320:120:0;;;7548:21:1;7605:2;7585:18;;;7578:30;7644:34;7624:18;;;7617:62;-1:-1:-1;;;7695:18:1;;;7688:45;7750:19;;26320:120:0;7364:411:1;26320:120:0;26453:26;26465:4;26471:7;26453:11;:26::i;82473:422::-;82670:10;82589:4;82652:29;;;:17;:29;;;;;;;;-1:-1:-1;;;;;82652:62:0;;;;;;;;;;:78;;82719:10;82652:66;:78::i;:::-;82629:10;82611:29;;;;:17;:29;;;;;;;;-1:-1:-1;;;;;82611:38:0;;;;;;;;;;;;:119;;;82746;643:25:1;;;82611:38:0;;-1:-1:-1;;;;;;;;;;;82746:119:0;616:18:1;82746:119:0;497:177:1;74198:205:0;74258:4;74283:34;-1:-1:-1;;;;;;;;;;;174:10:0;22906:197;:::i;74283:34::-;74275:68;;;;-1:-1:-1;;;74275:68:0;;;;;;;:::i;:::-;74356:17;74362:2;74366:6;74356:5;:17::i;:::-;-1:-1:-1;74391:4:0;74198:205;;;;:::o;75226:78::-;75283:13;75289:6;75283:5;:13::i;:::-;75226:78;:::o;80277:130::-;-1:-1:-1;;;;;80381:17:0;;80339:7;80381:17;;;:12;:17;;;;;;80366:33;;:14;:33::i;62060:103::-;61298:13;:11;:13::i;:::-;62125:30:::1;62152:1;62125:18;:30::i;:::-;62060:103::o:0;88886:84::-;61298:13;:11;:13::i;:::-;88940:14:::1;:22:::0;;-1:-1:-1;;88940:22:0::1;::::0;;88886:84::o;88978:138::-;61298:13;:11;:13::i;:::-;-1:-1:-1;;;;;89068:33:0;;;::::1;;::::0;;;:25:::1;:33;::::0;;;;:40;;-1:-1:-1;;89068:40:0::1;::::0;::::1;;::::0;;;::::1;::::0;;88978:138::o;60010:164::-;60087:46;60103:7;174:10;60126:6;60087:15;:46::i;:::-;60144:22;60150:7;60159:6;60144:5;:22::i;84810:1402::-;84926:7;84954:35;60479:25;174:10;22906:197;:::i;84954:35::-;84946:70;;;;-1:-1:-1;;;84946:70:0;;7982:2:1;84946:70:0;;;7964:21:1;8021:2;8001:18;;;7994:30;-1:-1:-1;;;8040:18:1;;;8033:52;8102:18;;84946:70:0;7780:346:1;84946:70:0;85055:10;85069:1;85055:15;85051:138;;85106:17;;85092:51;;;8333:25:1;;;8389:2;8374:18;;8367:34;;;8417:18;;;8410:34;;;;85092:51:0;;8321:2:1;8306:18;85092:51:0;;;;;;;;-1:-1:-1;85165:12:0;;85158:19;;85051:138;85256:17;;85291:8;85286:623;;85393:89;70603:6;85393:61;85433:20;70603:6;85442:10;85433:8;:20::i;:::-;85393:17;;;:39;:61::i;:::-;:83;;:89::i;:::-;85373:17;:109;85286:623;;;85572:24;85599:89;70603:6;85599:61;85639:20;70603:6;85648:10;85639:8;:20::i;85599:89::-;85572:116;;85726:19;:17;:19::i;:::-;85707:16;:38;85703:195;;;85766:17;:36;;;85703:195;;;85863:19;:17;:19::i;:::-;85843:17;:39;85703:195;85500:409;85286:623;85979:26;85994:10;;85979:14;:26::i;:::-;85964:12;:41;86030:6;;-1:-1:-1;;;;;86030:6:0;86022:29;86018:74;;86067:6;;;;;;;;;-1:-1:-1;;;;;86067:6:0;-1:-1:-1;;;;;86067:11:0;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86018:74;86156:17;;86119:55;;;8333:25:1;;;8389:2;8374:18;;8367:34;;;8417:18;;;8410:34;;;;86119:55:0;;;;;;8321:2:1;86119:55:0;;;-1:-1:-1;;86192:12:0;;84810:1402;;;;;;:::o;88220:104::-;61298:13;:11;:13::i;:::-;88294:8:::1;:22:::0;;-1:-1:-1;;;;;;88294:22:0::1;-1:-1:-1::0;;;;;88294:22:0;;;::::1;::::0;;;::::1;::::0;;88220:104::o;89264:135::-;61298:13;:11;:13::i;:::-;89328::::1;::::0;::::1;::::0;::::1;;;89327:14;89319:41;;;::::0;-1:-1:-1;;;89319:41:0;;8657:2:1;89319:41:0::1;::::0;::::1;8639:21:1::0;8696:2;8676:18;;;8669:30;-1:-1:-1;;;8715:18:1;;;8708:44;8769:18;;89319:41:0::1;8455:338:1::0;89319:41:0::1;89371:13;:20:::0;;-1:-1:-1;;89371:20:0::1;;;::::0;;89264:135::o;42303:203::-;42438:7;42470:18;;;:12;:18;;;;;:28;;42492:5;42470:21;:28::i;75956:223::-;76024:4;76049:34;-1:-1:-1;;;;;;;;;;;174:10:0;22906:197;:::i;76049:34::-;76041:68;;;;-1:-1:-1;;;76041:68:0;;;;;;;:::i;:::-;76122:27;76138:2;76142:6;76122:15;:27::i;88070:142::-;61298:13;:11;:13::i;:::-;88166:3:::1;88153:9;:16;;88145:25;;;::::0;::::1;;88181:11;:23:::0;88070:142::o;22906:197::-;23037:4;23066:12;;;;;;;;;;;-1:-1:-1;;;;;23066:29:0;;;;;;;;;;;;;;;22906:197::o;48028:104::-;48084:13;48117:7;48110:14;;;;;:::i;89407:138::-;61298:13;:11;:13::i;:::-;-1:-1:-1;;;;;89498:31:0;;;::::1;;::::0;;;:25:::1;:31;::::0;;;;:39;;-1:-1:-1;;89498:39:0::1;::::0;::::1;;::::0;;;::::1;::::0;;89407:138::o;83157:612::-;83337:10;83278:4;83319:29;;;:17;:29;;;;;;;;-1:-1:-1;;;;;83319:38:0;;;;;;;;;;83372:27;;;83368:237;;83434:10;83457:1;83416:29;;;:17;:29;;;;;;;;-1:-1:-1;;;;;83416:38:0;;;;;;;;;:42;83368:237;;;83532:61;:8;83563:15;83532:12;:61::i;:::-;83509:10;83491:29;;;;:17;:29;;;;;;;;-1:-1:-1;;;;;83491:38:0;;;;;;;;;:102;83368:237;83643:10;83690:29;;;;:17;:29;;;;;;;;-1:-1:-1;;;;;83620:119:0;;83690:38;;;;;;;;;;;83620:119;;643:25:1;;;83620:119:0;;83643:10;-1:-1:-1;;;;;;;;;;;83620:119:0;616:18:1;83620:119:0;497:177:1;49483:234:0;49598:4;174:10;49659:28;174:10;49676:2;49680:6;49659:9;:28::i;:::-;-1:-1:-1;49705:4:0;;49483:234;-1:-1:-1;;;49483:234:0:o;88455:115::-;88514:7;88541:21;88556:5;88541:14;:21::i;89124:132::-;61298:13;:11;:13::i;:::-;-1:-1:-1;;;;;89209:28:0;;;::::1;;::::0;;;:19:::1;:28;::::0;;;;:39;;-1:-1:-1;;89209:39:0::1;::::0;::::1;;::::0;;;::::1;::::0;;89124:132::o;42680:192::-;42805:7;42837:18;;;:12;:18;;;;;:27;;:25;:27::i;83814:988::-;84041:8;84022:15;:27;;84014:58;;;;-1:-1:-1;;;84014:58:0;;9000:2:1;84014:58:0;;;8982:21:1;9039:2;9019:18;;;9012:30;-1:-1:-1;;;9058:18:1;;;9051:48;9116:18;;84014:58:0;8798:342:1;84014:58:0;84190:16;;-1:-1:-1;;;;;84434:13:0;;84085:14;84434:13;;;:6;:13;;;;;:15;;84085:14;;84190:16;71175:66;;84336:5;;84368:7;;84402:5;;84434:15;84085:14;84434:15;;;:::i;:::-;;;;-1:-1:-1;84257:250:0;;;;;;9704:25:1;;;;-1:-1:-1;;;;;9803:15:1;;;9783:18;;;9776:43;9855:15;;;;9835:18;;;9828:43;9887:18;;;9880:34;9930:19;;;9923:35;9974:19;;;9967:35;;;9676:19;;84257:250:0;;;;;;;;;;;;84225:301;;;;;;84126:415;;;;;;;;-1:-1:-1;;;10271:27:1;;10323:1;10314:11;;10307:27;;;;10359:2;10350:12;;10343:28;10396:2;10387:12;;10013:392;84126:415:0;;;;-1:-1:-1;;84126:415:0;;;;;;;;;84102:450;;84126:415;84102:450;;;;;-1:-1:-1;;;;;;84573:19:0;;84565:53;;;;-1:-1:-1;;;84565:53:0;;10612:2:1;84565:53:0;;;10594:21:1;10651:2;10631:18;;;10624:30;-1:-1:-1;;;10670:18:1;;;10663:51;10731:18;;84565:53:0;10410:345:1;84565:53:0;84646:26;;;;;;;;;;;;10987:25:1;;;11060:4;11048:17;;11028:18;;;11021:45;;;;11082:18;;;11075:34;;;11125:18;;;11118:34;;;84646:26:0;;10959:19:1;;84646:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;84637:35:0;:5;-1:-1:-1;;;;;84637:35:0;;84629:66;;;;-1:-1:-1;;;84629:66:0;;11365:2:1;84629:66:0;;;11347:21:1;11404:2;11384:18;;;11377:30;-1:-1:-1;;;11423:18:1;;;11416:48;11481:18;;84629:66:0;11163:342:1;84629:66:0;-1:-1:-1;;;;;84706:24:0;;;;;;;:17;:24;;;;;;;;:33;;;;;;;;;;;;;:41;;;84763:31;;643:25:1;;;-1:-1:-1;;;;;;;;;;;84763:31:0;616:18:1;84763:31:0;;;;;;;84003:799;83814:988;;;;;;;:::o;25455:190::-;24602:7;24634:12;;;;;;;;;;:22;;;22426:16;22437:4;22426:10;:16::i;:::-;25611:26:::1;25623:4;25629:7;25611:11;:26::i;89622:212::-:0;61298:13;:11;:13::i;:::-;89769:4:::1;::::0;89739:44:::1;::::0;-1:-1:-1;;;89739:44:0;;-1:-1:-1;;;;;89769:4:0::1;::::0;;::::1;::::0;::::1;89739:44;::::0;::::1;11684:51:1::0;11751:18;;;11744:34;;;-1:-1:-1;;89739:29:0;::::1;::::0;::::1;::::0;11657:18:1;;89739:44:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;89727:56;;89802:4;89794:32;;;::::0;-1:-1:-1;;;89794:32:0;;12241:2:1;89794:32:0::1;::::0;::::1;12223:21:1::0;12280:2;12260:18;;;12253:30;-1:-1:-1;;;12299:18:1;;;12292:45;12354:18;;89794:32:0::1;12039:339:1::0;62318:238:0;61298:13;:11;:13::i;:::-;-1:-1:-1;;;;;62421:22:0;::::1;62399:110;;;::::0;-1:-1:-1;;;62399:110:0;;12585:2:1;62399:110:0::1;::::0;::::1;12567:21:1::0;12624:2;12604:18;;;12597:30;12663:34;12643:18;;;12636:62;-1:-1:-1;;;12714:18:1;;;12707:36;12760:19;;62399:110:0::1;12383:402:1::0;62399:110:0::1;62520:28;62539:8;62520:18;:28::i;22534:280::-:0;22664:4;-1:-1:-1;;;;;;22706:47:0;;-1:-1:-1;;;22706:47:0;;:100;;-1:-1:-1;;;;;;;;;;5242:40:0;;;22770:36;5083:207;87552:298;87643:34;-1:-1:-1;;;;;;;;;;;174:10:0;22906:197;:::i;87643:34::-;87635:68;;;;-1:-1:-1;;;87635:68:0;;;;;;;:::i;:::-;87714:13;87759;73475:12;;;73395:100;87759:13;87755:17;;:3;:17;:::i;:::-;87742:11;;87730;:6;87737:4;87730:11;:::i;:::-;:23;;;;:::i;:::-;:43;;;;:::i;:::-;87714:59;;87784:23;87790:8;87800:6;87784:5;:23::i;:::-;87818:24;87826:1;87829:5;87836;87818:7;:24::i;:::-;;87624:226;87552:298;;:::o;73768:313::-;73820:7;74063:10;;-1:-1:-1;;74041:32:0;;;;:::i;66173:98::-;66231:7;66258:5;66262:1;66258;:5;:::i;88731:147::-;88852:17;;88793:7;;88820:50;;:27;:5;70497:6;88820:9;:27::i;65792:98::-;65850:7;65877:5;65881:1;65877;:5;:::i;88578:145::-;88639:7;88666:49;70497:6;88666:27;88675:17;;88666:4;:8;;:27;;;;:::i;23407:105::-;23474:30;23485:4;174:10;23474;:30::i;42965:201::-;43085:31;43102:4;43108:7;43085:16;:31::i;:::-;43127:18;;;;:12;:18;;;;;:31;;43150:7;43127:22;:31::i;61577:132::-;61485:6;;-1:-1:-1;;;;;61485:6:0;174:10;61641:23;61633:68;;;;-1:-1:-1;;;61633:68:0;;13650:2:1;61633:68:0;;;13632:21:1;;;13669:18;;;13662:30;13728:34;13708:18;;;13701:62;13780:18;;61633:68:0;13448:356:1;43260:206:0;43381:32;43399:4;43405:7;43381:17;:32::i;:::-;43424:18;;;;:12;:18;;;;;:34;;43450:7;43424:25;:34::i;74411:685::-;74531:12;;:24;;74548:6;74531:16;:24::i;:::-;74516:12;:39;74601:16;74620:22;74635:6;74620:14;:22::i;:::-;74700:10;;74601:41;;-1:-1:-1;74700:24:0;;74601:41;74700:14;:24::i;:::-;74687:10;:37;74847:19;:17;:19::i;:::-;74826:17;;:40;;74804:116;;;;-1:-1:-1;;;74804:116:0;;14011:2:1;74804:116:0;;;13993:21:1;14050:2;14030:18;;;14023:30;14089:28;14069:18;;;14062:56;14135:18;;74804:116:0;13809:350:1;74804:116:0;-1:-1:-1;;;;;74976:16:0;;;;;;:12;:16;;;;;;:30;;74997:8;74976:20;:30::i;:::-;-1:-1:-1;;;;;74957:16:0;;;;;;:12;:16;;;;;;;;;:49;;;;75024:16;;11684:51:1;;;11751:18;;;11744:34;;;75024:16:0;;11657:18:1;75024:16:0;;;;;;;75056:32;;643:25:1;;;-1:-1:-1;;;;;75056:32:0;;;75073:1;;-1:-1:-1;;;;;;;;;;;75056:32:0;631:2:1;616:18;75056:32:0;;;;;;;;74472:624;74411:685;;:::o;75312:503::-;75411:12;;:24;;75428:6;75411:16;:24::i;:::-;75396:12;:39;75481:16;75500:22;75515:6;75500:14;:22::i;:::-;75580:10;;75481:41;;-1:-1:-1;75580:24:0;;75481:41;75580:14;:24::i;:::-;75567:10;:37;75686:10;75673:24;;;;:12;:24;;;;;;:38;;75702:8;75673:28;:38::i;:::-;75659:10;75646:24;;;;:12;:24;;;;;;;;;:65;;;;75727:24;;11684:51:1;;;11751:18;;;11744:34;;;75727:24:0;;11657:18:1;75727:24:0;;;;;;;75767:40;;643:25:1;;;75796:1:0;;75776:10;;-1:-1:-1;;;;;;;;;;;75767:40:0;631:2:1;616:18;75767:40:0;;;;;;;75352:463;75312:503;:::o;62716:191::-;62809:6;;;-1:-1:-1;;;;;62826:17:0;;;-1:-1:-1;;;;;;62826:17:0;;;;;;;62859:40;;62809:6;;;62826:17;62809:6;;62859:40;;62790:16;;62859:40;62779:128;62716:191;:::o;57404:502::-;-1:-1:-1;;;;;81165:25:0;;;57539:24;81165:25;;;:17;:25;;;;;;;;:34;;;;;;;;;;-1:-1:-1;;57606:37:0;;57602:297;;57706:6;57686:16;:26;;57660:117;;;;-1:-1:-1;;;57660:117:0;;14366:2:1;57660:117:0;;;14348:21:1;14405:2;14385:18;;;14378:30;14444:31;14424:18;;;14417:59;14493:18;;57660:117:0;14164:353:1;57660:117:0;57821:51;57830:5;57837:7;57865:6;57846:16;:25;57821:8;:51::i;55620:675::-;-1:-1:-1;;;;;55704:21:0;;55696:67;;;;-1:-1:-1;;;55696:67:0;;14724:2:1;55696:67:0;;;14706:21:1;14763:2;14743:18;;;14736:30;14802:34;14782:18;;;14775:62;-1:-1:-1;;;14853:18:1;;;14846:31;14894:19;;55696:67:0;14522:397:1;55696:67:0;-1:-1:-1;;;;;55863:18:0;;55838:22;55863:18;;;:9;:18;;;;;;55900:24;;;;55892:71;;;;-1:-1:-1;;;55892:71:0;;15126:2:1;55892:71:0;;;15108:21:1;15165:2;15145:18;;;15138:30;15204:34;15184:18;;;15177:62;-1:-1:-1;;;15255:18:1;;;15248:32;15297:19;;55892:71:0;14924:398:1;55892:71:0;-1:-1:-1;;;;;55999:18:0;;;;;;:9;:18;;;;;;;;56020:23;;;55999:44;;56138:12;:22;;;;;;;56189:37;643:25:1;;;55999:18:0;;;-1:-1:-1;;;;;;;;;;;56189:37:0;616:18:1;56189:37:0;;;;;;;24974:188;;;:::o;66530:98::-;66588:7;66615:5;66619:1;66615;:5;:::i;66929:98::-;66987:7;67014:5;67018:1;67014;:5;:::i;37355:190::-;37456:7;37512:22;37516:3;37528:5;37512:3;:22::i;76187:702::-;76305:10;;:22;;76320:6;76305:14;:22::i;:::-;76292:10;:35;76371:20;76394:22;76409:6;76394:14;:22::i;:::-;76477:12;;76371:45;;-1:-1:-1;76477:30:0;;76371:45;76477:16;:30::i;:::-;76462:12;:45;76630:19;:17;:19::i;:::-;76609:17;;:40;;76587:116;;;;-1:-1:-1;;;76587:116:0;;14011:2:1;76587:116:0;;;13993:21:1;14050:2;14030:18;;;14023:30;14089:28;14069:18;;;14062:56;14135:18;;76587:116:0;13809:350:1;76587:116:0;-1:-1:-1;;;;;76759:16:0;;;;;;:12;:16;;;;;;:28;;76780:6;76759:20;:28::i;:::-;-1:-1:-1;;;;;76740:16:0;;;;;;:12;:16;;;;;;;;;:47;;;;76805:22;;11684:51:1;;;11751:18;;;11744:34;;;76805:22:0;;11657:18:1;76805:22:0;;;;;;;76843:38;;643:25:1;;;-1:-1:-1;;;;;76843:38:0;;;76860:1;;-1:-1:-1;;;;;;;;;;;76843:38:0;631:2:1;616:18;76843:38:0;497:177:1;77614:1675:0;77734:2;-1:-1:-1;;;;;71714:18:0;;71706:27;;;;;;71766:4;-1:-1:-1;;;;;71752:19:0;;;71744:28;;;;;;78029:16:::1;78048:21;78063:5;78048:14;:21::i;:::-;78086:14;::::0;78029:40;;-1:-1:-1;78086:14:0::1;;78082:951;;;61485:6:::0;;-1:-1:-1;;;;;78117:15:0;;::::1;61485:6:::0;;78117:15:::1;::::0;::::1;::::0;:32:::1;;-1:-1:-1::0;61485:6:0;;-1:-1:-1;;;;;78136:13:0;;::::1;61485:6:::0;;78136:13:::1;;78117:32;:57;;;;-1:-1:-1::0;;;;;;78153:21:0;::::1;78167:6;78153:21;;78117:57;78113:915;;;78194:13;::::0;::::1;::::0;::::1;;;78189:133;;-1:-1:-1::0;;;;;78232:25:0;::::1;;::::0;;;:19:::1;:25;::::0;;;;;::::1;;::::0;:52:::1;;-1:-1:-1::0;;;;;;78261:23:0;::::1;;::::0;;;:19:::1;:23;::::0;;;;;::::1;;78232:52;78224:87;;;::::0;-1:-1:-1;;;78224:87:0;;15529:2:1;78224:87:0::1;::::0;::::1;15511:21:1::0;15568:2;15548:18;;;15541:30;-1:-1:-1;;;15587:18:1;;;15580:52;15649:18;;78224:87:0::1;15327:346:1::0;78224:87:0::1;-1:-1:-1::0;;;;;78358:31:0;::::1;;::::0;;;:25:::1;:31;::::0;;;;;::::1;;:65:::0;::::1;;;-1:-1:-1::0;;;;;;78394:29:0;::::1;;::::0;;;:25:::1;:29;::::0;;;;;::::1;;78393:30;78358:65;78354:665;;;78459:18;;78447:8;:30;;78439:90;;;::::0;-1:-1:-1;;;78439:90:0;;15880:2:1;78439:90:0::1;::::0;::::1;15862:21:1::0;15919:2;15899:18;;;15892:30;15958:34;15938:18;;;15931:62;-1:-1:-1;;;16009:18:1;;;16002:45;16064:19;;78439:90:0::1;15678:411:1::0;78439:90:0::1;78589:13;::::0;-1:-1:-1;;;;;80683:17:0;;80656:7;80683:17;;;:12;:17;;;;;;78551:34:::1;::::0;:8;:34:::1;:::i;:::-;:51;;78543:83;;;::::0;-1:-1:-1;;;78543:83:0;;16296:2:1;78543:83:0::1;::::0;::::1;16278:21:1::0;16335:2;16315:18;;;16308:30;-1:-1:-1;;;16354:18:1;;;16347:49;16413:18;;78543:83:0::1;16094:343:1::0;78543:83:0::1;78354:665;;;-1:-1:-1::0;;;;;78680:29:0;::::1;;::::0;;;:25:::1;:29;::::0;;;;;::::1;;:65:::0;::::1;;;-1:-1:-1::0;;;;;;78714:31:0;::::1;;::::0;;;:25:::1;:31;::::0;;;;;::::1;;78713:32;78680:65;78676:343;;;78781:18;;78769:8;:30;;78761:91;;;::::0;-1:-1:-1;;;78761:91:0;;16644:2:1;78761:91:0::1;::::0;::::1;16626:21:1::0;16683:2;16663:18;;;16656:30;16722:34;16702:18;;;16695:62;-1:-1:-1;;;16773:18:1;;;16766:46;16829:19;;78761:91:0::1;16442:412:1::0;78676:343:0::1;-1:-1:-1::0;;;;;78877:29:0;::::1;;::::0;;;:25:::1;:29;::::0;;;;;::::1;;78872:147;;78968:13;::::0;-1:-1:-1;;;;;80683:17:0;;80656:7;80683:17;;;:12;:17;;;;;;78930:34:::1;::::0;:8;:34:::1;:::i;:::-;:51;;78922:83;;;::::0;-1:-1:-1;;;78922:83:0;;16296:2:1;78922:83:0::1;::::0;::::1;16278:21:1::0;16335:2;16315:18;;;16308:30;-1:-1:-1;;;16354:18:1;;;16347:49;16413:18;;78922:83:0::1;16094:343:1::0;78922:83:0::1;-1:-1:-1::0;;;;;79105:18:0;::::1;;::::0;;;:12:::1;:18;::::0;;;;;:32:::1;::::0;79128:8;79105:22:::1;:32::i;:::-;-1:-1:-1::0;;;;;79084:18:0;;::::1;;::::0;;;:12:::1;:18;::::0;;;;;:53;;;;79208:16;;::::1;::::0;;;;:30:::1;::::0;79229:8;79208:20:::1;:30::i;:::-;-1:-1:-1::0;;;;;79189:16:0;;::::1;;::::0;;;:12:::1;:16;::::0;;;;;;:49;;;;79254:25;;;;::::1;::::0;-1:-1:-1;;;;;;;;;;;79254:25:0;::::1;::::0;79273:5;643:25:1;;631:2;616:18;;497:177;79254:25:0::1;;;;;;;;77743:1546;77614:1675:::0;;;;:::o;36884:117::-;36947:7;36974:19;36982:3;31931:18;;31848:109;86220:1322;86339:7;86387:10;86401:1;86387:15;86383:138;;86438:17;;86424:51;;;8333:25:1;;;8389:2;8374:18;;8367:34;;;8417:18;;;8410:34;;;;86424:51:0;;8321:2:1;8306:18;86424:51:0;8131:319:1;23802:492:0;23891:22;23899:4;23905:7;23891;:22::i;:::-;23886:401;;24079:28;24099:7;24079:19;:28::i;:::-;24180:38;24208:4;24215:2;24180:19;:38::i;:::-;23984:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;23984:257:0;;;;;;;;;;-1:-1:-1;;;23930:345:0;;;;;;;:::i;27866:238::-;27950:22;27958:4;27964:7;27950;:22::i;:::-;27945:152;;27989:6;:12;;;;;;;;;;;-1:-1:-1;;;;;27989:29:0;;;;;;;;;:36;;-1:-1:-1;;27989:36:0;28021:4;27989:36;;;28072:12;174:10;;94:98;28072:12;-1:-1:-1;;;;;28045:40:0;28063:7;-1:-1:-1;;;;;28045:40:0;28057:4;28045:40;;;;;;;;;;27866:238;;:::o;35981:175::-;36069:4;36098:50;36103:3;-1:-1:-1;;;;;36123:23:0;;36098:4;:50::i;28284:239::-;28368:22;28376:4;28382:7;28368;:22::i;:::-;28364:152;;;28439:5;28407:12;;;;;;;;;;;-1:-1:-1;;;;;28407:29:0;;;;;;;;;;:37;;-1:-1:-1;;28407:37:0;;;28464:40;174:10;;28407:12;;28464:40;;28439:5;28464:40;28284:239;;:::o;36332:181::-;36423:4;36452:53;36460:3;-1:-1:-1;;;;;36480:23:0;;36452:7;:53::i;56733:380::-;-1:-1:-1;;;;;56869:19:0;;56861:68;;;;-1:-1:-1;;;56861:68:0;;17878:2:1;56861:68:0;;;17860:21:1;17917:2;17897:18;;;17890:30;17956:34;17936:18;;;17929:62;-1:-1:-1;;;18007:18:1;;;18000:34;18051:19;;56861:68:0;17676:400:1;56861:68:0;-1:-1:-1;;;;;56948:21:0;;56940:68;;;;-1:-1:-1;;;56940:68:0;;18283:2:1;56940:68:0;;;18265:21:1;18322:2;18302:18;;;18295:30;18361:34;18341:18;;;18334:62;-1:-1:-1;;;18412:18:1;;;18405:32;18454:19;;56940:68:0;18081:398:1;56940:68:0;-1:-1:-1;;;;;57021:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;57073:32;;643:25:1;;;-1:-1:-1;;;;;;;;;;;57073:32:0;616:18:1;57073:32:0;497:177:1;32311:152:0;32405:7;32437:3;:11;;32449:5;32437:18;;;;;;;;:::i;:::-;;;;;;;;;32430:25;;32311:152;;;;:::o;21475:151::-;21533:13;21566:52;-1:-1:-1;;;;;21578:22:0;;19598:2;20839:479;20941:13;20972:19;21004:10;21008:6;21004:1;:10;:::i;:::-;:14;;21017:1;21004:14;:::i;:::-;20994:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;20994:25:0;;20972:47;;-1:-1:-1;;;21030:6:0;21037:1;21030:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;21030:15:0;;;;;;;;;-1:-1:-1;;;21056:6:0;21063:1;21056:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;21056:15:0;;;;;;;;-1:-1:-1;21087:9:0;21099:10;21103:6;21099:1;:10;:::i;:::-;:14;;21112:1;21099:14;:::i;:::-;21087:26;;21082:131;21119:1;21115;:5;21082:131;;;-1:-1:-1;;;21163:5:0;21171:3;21163:11;21154:21;;;;;;;:::i;:::-;;;;21142:6;21149:1;21142:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;21142:33:0;;;;;;;;-1:-1:-1;21200:1:0;21190:11;;;;;21122:3;;;:::i;:::-;;;21082:131;;;-1:-1:-1;21231:10:0;;21223:55;;;;-1:-1:-1;;;21223:55:0;;19091:2:1;21223:55:0;;;19073:21:1;;;19110:18;;;19103:30;19169:34;19149:18;;;19142:62;19221:18;;21223:55:0;18889:356:1;29504:414:0;29567:4;31730:19;;;:12;;;:19;;;;;;29584:327;;-1:-1:-1;29627:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;29810:18;;29788:19;;;:12;;;:19;;;;;;:40;;;;29843:11;;29584:327;-1:-1:-1;29894:5:0;29887:12;;30094:1421;30160:4;30299:19;;;:12;;;:19;;;;;;30335:15;;30331:1177;;30710:21;30734:14;30747:1;30734:10;:14;:::i;:::-;30783:18;;30710:38;;-1:-1:-1;30763:17:0;;30783:22;;30804:1;;30783:22;:::i;:::-;30763:42;;30839:13;30826:9;:26;30822:405;;30873:17;30893:3;:11;;30905:9;30893:22;;;;;;;;:::i;:::-;;;;;;;;;30873:42;;31047:9;31018:3;:11;;31030:13;31018:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;31132:23;;;:12;;;:23;;;;;:36;;;30822:405;31308:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;31403:3;:12;;:19;31416:5;31403:19;;;;;;;;;;;31396:26;;;31446:4;31439:11;;;;;;;30331:1177;31490:5;31483:12;;;;;14:286:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:1;;209:43;;199:71;;266:1;263;256:12;679:250;764:1;774:113;788:6;785:1;782:13;774:113;;;864:11;;;858:18;845:11;;;838:39;810:2;803:10;774:113;;;-1:-1:-1;;921:1:1;903:16;;896:27;679:250::o;934:396::-;1083:2;1072:9;1065:21;1046:4;1115:6;1109:13;1158:6;1153:2;1142:9;1138:18;1131:34;1174:79;1246:6;1241:2;1230:9;1226:18;1221:2;1213:6;1209:15;1174:79;:::i;:::-;1314:2;1293:15;-1:-1:-1;;1289:29:1;1274:45;;;;1321:2;1270:54;;934:396;-1:-1:-1;;934:396:1:o;1335:131::-;-1:-1:-1;;;;;1410:31:1;;1400:42;;1390:70;;1456:1;1453;1446:12;1471:315;1539:6;1547;1600:2;1588:9;1579:7;1575:23;1571:32;1568:52;;;1616:1;1613;1606:12;1568:52;1655:9;1642:23;1674:31;1699:5;1674:31;:::i;:::-;1724:5;1776:2;1761:18;;;;1748:32;;-1:-1:-1;;;1471:315:1:o;2193:456::-;2270:6;2278;2286;2339:2;2327:9;2318:7;2314:23;2310:32;2307:52;;;2355:1;2352;2345:12;2307:52;2394:9;2381:23;2413:31;2438:5;2413:31;:::i;:::-;2463:5;-1:-1:-1;2520:2:1;2505:18;;2492:32;2533:33;2492:32;2533:33;:::i;:::-;2193:456;;2585:7;;-1:-1:-1;;;2639:2:1;2624:18;;;;2611:32;;2193:456::o;2654:180::-;2713:6;2766:2;2754:9;2745:7;2741:23;2737:32;2734:52;;;2782:1;2779;2772:12;2734:52;-1:-1:-1;2805:23:1;;2654:180;-1:-1:-1;2654:180:1:o;3024:315::-;3092:6;3100;3153:2;3141:9;3132:7;3128:23;3124:32;3121:52;;;3169:1;3166;3159:12;3121:52;3205:9;3192:23;3182:33;;3265:2;3254:9;3250:18;3237:32;3278:31;3303:5;3278:31;:::i;:::-;3328:5;3318:15;;;3024:315;;;;;:::o;3344:259::-;3415:6;3468:2;3456:9;3447:7;3443:23;3439:32;3436:52;;;3484:1;3481;3474:12;3436:52;3523:9;3510:23;3542:31;3567:5;3542:31;:::i;4257:118::-;4343:5;4336:13;4329:21;4322:5;4319:32;4309:60;;4365:1;4362;4355:12;4380:382;4445:6;4453;4506:2;4494:9;4485:7;4481:23;4477:32;4474:52;;;4522:1;4519;4512:12;4474:52;4561:9;4548:23;4580:31;4605:5;4580:31;:::i;:::-;4630:5;-1:-1:-1;4687:2:1;4672:18;;4659:32;4700:30;4659:32;4700:30;:::i;4767:377::-;4841:6;4849;4857;4910:2;4898:9;4889:7;4885:23;4881:32;4878:52;;;4926:1;4923;4916:12;4878:52;4962:9;4949:23;4939:33;;5019:2;5008:9;5004:18;4991:32;4981:42;;5073:2;5062:9;5058:18;5045:32;5086:28;5108:5;5086:28;:::i;:::-;5133:5;5123:15;;;4767:377;;;;;:::o;5149:248::-;5217:6;5225;5278:2;5266:9;5257:7;5253:23;5249:32;5246:52;;;5294:1;5291;5284:12;5246:52;-1:-1:-1;;5317:23:1;;;5387:2;5372:18;;;5359:32;;-1:-1:-1;5149:248:1:o;5402:829::-;5513:6;5521;5529;5537;5545;5553;5561;5614:3;5602:9;5593:7;5589:23;5585:33;5582:53;;;5631:1;5628;5621:12;5582:53;5670:9;5657:23;5689:31;5714:5;5689:31;:::i;:::-;5739:5;-1:-1:-1;5796:2:1;5781:18;;5768:32;5809:33;5768:32;5809:33;:::i;:::-;5861:7;-1:-1:-1;5915:2:1;5900:18;;5887:32;;-1:-1:-1;5966:2:1;5951:18;;5938:32;;-1:-1:-1;6022:3:1;6007:19;;5994:33;6071:4;6058:18;;6046:31;;6036:59;;6091:1;6088;6081:12;6036:59;5402:829;;;;-1:-1:-1;5402:829:1;;;;6114:7;6168:3;6153:19;;6140:33;;-1:-1:-1;6220:3:1;6205:19;;;6192:33;;5402:829;-1:-1:-1;;5402:829:1:o;6236:388::-;6304:6;6312;6365:2;6353:9;6344:7;6340:23;6336:32;6333:52;;;6381:1;6378;6371:12;6333:52;6420:9;6407:23;6439:31;6464:5;6439:31;:::i;:::-;6489:5;-1:-1:-1;6546:2:1;6531:18;;6518:32;6559:33;6518:32;6559:33;:::i;6629:380::-;6708:1;6704:12;;;;6751;;;6772:61;;6826:4;6818:6;6814:17;6804:27;;6772:61;6879:2;6871:6;6868:14;6848:18;6845:38;6842:161;;6925:10;6920:3;6916:20;6913:1;6906:31;6960:4;6957:1;6950:15;6988:4;6985:1;6978:15;6842:161;;6629:380;;;:::o;7014:345::-;7216:2;7198:21;;;7255:2;7235:18;;;7228:30;-1:-1:-1;;;7289:2:1;7274:18;;7267:51;7350:2;7335:18;;7014:345::o;9145:127::-;9206:10;9201:3;9197:20;9194:1;9187:31;9237:4;9234:1;9227:15;9261:4;9258:1;9251:15;9277:135;9316:3;9337:17;;;9334:43;;9357:18;;:::i;:::-;-1:-1:-1;9404:1:1;9393:13;;9277:135::o;11789:245::-;11856:6;11909:2;11897:9;11888:7;11884:23;11880:32;11877:52;;;11925:1;11922;11915:12;11877:52;11957:9;11951:16;11976:28;11998:5;11976:28;:::i;12790:168::-;12863:9;;;12894;;12911:15;;;12905:22;;12891:37;12881:71;;12932:18;;:::i;12963:217::-;13003:1;13029;13019:132;;13073:10;13068:3;13064:20;13061:1;13054:31;13108:4;13105:1;13098:15;13136:4;13133:1;13126:15;13019:132;-1:-1:-1;13165:9:1;;12963:217::o;13185:128::-;13252:9;;;13273:11;;;13270:37;;;13287:18;;:::i;13318:125::-;13383:9;;;13404:10;;;13401:36;;;13417:18;;:::i;16859:812::-;17270:25;17265:3;17258:38;17240:3;17325:6;17319:13;17341:75;17409:6;17404:2;17399:3;17395:12;17388:4;17380:6;17376:17;17341:75;:::i;:::-;-1:-1:-1;;;17475:2:1;17435:16;;;17467:11;;;17460:40;17525:13;;17547:76;17525:13;17609:2;17601:11;;17594:4;17582:17;;17547:76;:::i;:::-;17643:17;17662:2;17639:26;;16859:812;-1:-1:-1;;;;16859:812:1:o;18484:127::-;18545:10;18540:3;18536:20;18533:1;18526:31;18576:4;18573:1;18566:15;18600:4;18597:1;18590:15;18616:127;18677:10;18672:3;18668:20;18665:1;18658:31;18708:4;18705:1;18698:15;18732:4;18729:1;18722:15;18748:136;18787:3;18815:5;18805:39;;18824:18;;:::i;:::-;-1:-1:-1;;;18860:18:1;;18748:136::o;19250:127::-;19311:10;19306:3;19302:20;19299:1;19292:31;19342:4;19339:1;19332:15;19366:4;19363:1;19356:15

Swarm Source

ipfs://c3a0c3968ed5101c18217aa716b3d306d14c1b88d8249420bbace1c7ae480418
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.