Token Option to buy BVM

 

Overview [ERC-20]

Price
$0.00 @ 0.000000 Eth
Fully Diluted Market Cap
Max Total Supply:
554,339.843698704219433454 oBVM

Holders:
793

Transfers:
-

Contract:
0x762eb51D2e779EeEc9B239FFB0B2eC8262848f3E0x762eb51D2e779EeEc9B239FFB0B2eC8262848f3E

Decimals:
18

Social Profiles:
Not Available, Update ?

Loading
[ Download CSV Export  ] 
Loading
[ Download CSV Export  ] 
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
OptionTokenV3

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at basescan.org on 2023-08-02
*/

// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.13;


// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)




// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)



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

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

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

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

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

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

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

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


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)



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

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


// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)




// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)



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

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

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

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


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

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

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

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

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

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

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


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)




// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)



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


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


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

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

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

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

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

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

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

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

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

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

        _revokeRole(role, account);
    }

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

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

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

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




/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

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

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}



interface IERC20 {
    function totalSupply() external view returns (uint256);
    function transfer(address recipient, uint amount) external returns (bool);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function balanceOf(address) external view returns (uint);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}


interface IFlow {
    function totalSupply() external view returns (uint);
    function balanceOf(address) external view returns (uint);
    function approve(address spender, uint value) external returns (bool);
    function transfer(address, uint) external returns (bool);
    function transferFrom(address,address,uint) external returns (bool);
    function mint(address, uint) external returns (bool);
    function minter() external returns (address);
}



interface IGaugeV2 {
    function left(address token) external view returns (uint);
    function notifyRewardAmount(address token, uint amount) external;

    function depositWithLock(
        address account,
        uint256 amount,
        uint256 _lockDuration
    ) external;
}



interface IVoter {
    function _ve() external view returns (address);
    function governor() external view returns (address);
    function emergencyCouncil() external view returns (address);
    function attachTokenToGauge(uint _tokenId, address account) external;
    function detachTokenFromGauge(uint _tokenId, address account) external;
    function emitDeposit(uint _tokenId, address account, uint amount) external;
    function emitWithdraw(uint _tokenId, address account, uint amount) external;
    function isWhitelisted(address token) external view returns (bool);
    function notifyRewardAmount(uint amount) external;
    function distribute(address _gauge) external;
    function gauges(address) external view returns (address);
}



interface IVotingEscrow {

    struct Point {
        int128 bias;
        int128 slope; // # -dweight / dt
        uint256 ts;
        uint256 blk; // block
    }

    function token() external view returns (address);
    function team() external returns (address);
    function epoch() external view returns (uint);
    function point_history(uint loc) external view returns (Point memory);
    function user_point_history(uint tokenId, uint loc) external view returns (Point memory);
    function user_point_epoch(uint tokenId) external view returns (uint);

    function ownerOf(uint) external view returns (address);
    function isApprovedOrOwner(address, uint) external view returns (bool);
    function transferFrom(address, address, uint) external;

    function voting(uint tokenId) external;
    function abstain(uint tokenId) external;
    function attach(uint tokenId) external;
    function detach(uint tokenId) external;

    function checkpoint() external;
    function deposit_for(uint tokenId, uint value) external;
    function create_lock_for(uint, uint, address) external returns (uint);

    function balanceOfNFT(uint) external view returns (uint);
    function totalSupply() external view returns (uint);
}



interface IPair {
    function metadata() external view returns (uint dec0, uint dec1, uint r0, uint r1, bool st, address t0, address t1);
    function tokens() external returns (address, address);
    function token0() external returns (address);
    function token1() external returns (address);
    function externalBribe() external returns (address);
    function transferFrom(address src, address dst, uint amount) external returns (bool);
    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function burn(address to) external returns (uint amount0, uint amount1);
    function mint(address to) external returns (uint liquidity);
    function getReserves() external view returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast);
    function getAmountOut(uint, address) external view returns (uint);
    function setHasGauge(bool value) external;
    function setExternalBribe(address _externalBribe) external;
    function hasGauge() external view returns (bool);
    function stable() external view returns (bool);
    function prices(address tokenIn, uint amountIn, uint points) external view returns (uint[] memory);
}



interface IRouter {
    function pairFor(address tokenA, address tokenB, bool stable) external view returns (address pair);
    function swapExactTokensForTokensSimple(uint amountIn, uint amountOutMin, address tokenFrom, address tokenTo, bool stable, address to, uint deadline) external returns (uint[] memory amounts);
    function getAmountOut(uint amountIn, address tokenIn, address tokenOut, bool stable) external view returns (uint amount);
	function getReserves(address tokenA, address tokenB, bool stable) external view returns (uint, uint);
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint, uint, uint);
}


/// @title Option Token
/// @notice Option token representing the right to purchase the underlying token
/// at TWAP reduced rate. Similar to call options but with a variable strike
/// price that's always at a certain discount to the market price.
/// @dev Assumes the underlying token and the payment token both use 18 decimals and revert on
// failure to transfer.

contract OptionTokenV3 is ERC20, AccessControl {
    /// -----------------------------------------------------------------------
    /// Constants
    /// -----------------------------------------------------------------------
    uint256 public constant MAX_DISCOUNT = 100; // 100%
    uint256 public constant MIN_DISCOUNT = 0; // 0%
    uint256 public constant MAX_TWAP_POINTS = 50; // 25 hours
    uint256 public constant FULL_LOCK = 52 * 7 * 86400; // 52 weeks
    uint256 public constant MAX_FEES = 50; // 50%

    /// -----------------------------------------------------------------------
    /// Roles
    /// -----------------------------------------------------------------------
    /// @dev The identifier of the role which maintains other roles and settings
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");

    /// @dev The identifier of the role which is allowed to mint options token
    bytes32 public constant MINTER_ROLE = keccak256("MINTER");

    /// @dev The identifier of the role which allows accounts to pause execrcising options
    /// in case of emergency
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER");

    /// -----------------------------------------------------------------------
    /// Errors
    /// -----------------------------------------------------------------------
    error OptionToken_PastDeadline();
    error OptionToken_NoAdminRole();
    error OptionToken_NoMinterRole();
    error OptionToken_NoPauserRole();
    error OptionToken_SlippageTooHigh();
    error OptionToken_InvalidDiscount();
    error OptionToken_InvalidLockDuration();
    error OptionToken_InvalidFee();
    error OptionToken_Paused();
    error OptionToken_InvalidTwapPoints();
    error OptionToken_IncorrectPairToken();

    /// -----------------------------------------------------------------------
    /// Events
    /// -----------------------------------------------------------------------

    event Exercise(
        address indexed sender,
        address indexed recipient,
        uint256 amount,
        uint256 paymentAmount
    );
    event ExerciseVe(
        address indexed sender,
        address indexed recipient,
        uint256 amount,
        uint256 paymentAmount,
        uint256 nftId
    );
    event ExerciseLp(
        address indexed sender,
        address indexed recipient,
        uint256 amount,
        uint256 paymentAmount,
        uint256 lpAmount
    );
    event SetPairAndPaymentToken(
        IPair indexed newPair,
        address indexed newPaymentToken
    );
    event SetGauge(address indexed newGauge);
    event SetTreasury(address indexed newTreasury,address indexed newVMTreasury);
    event SetFees(uint256 newTeamFee,uint256 newVMFee);
    event SetRouter(address indexed newRouter);
    event SetDiscount(uint256 discount);
    event SetVeDiscount(uint256 veDiscount);
    event SetMinLPDiscount(uint256 lpMinDiscount);
    event SetMaxLPDiscount(uint256 lpMaxDiscount);
    event SetLockDurationForMaxLpDiscount(uint256 lockDurationForMaxLpDiscount);
    event SetLockDurationForMinLpDiscount(uint256 lockDurationForMinLpDiscount);
    event PauseStateChanged(bool isPaused);
    event SetTwapPoints(uint256 twapPoints);

    /// -----------------------------------------------------------------------
    /// Immutable parameters
    /// -----------------------------------------------------------------------

    /// @notice The token paid by the options token holder during redemption
    address public paymentToken;

    /// @notice The underlying token purchased during redemption
    address public immutable underlyingToken;

    /// @notice The voting escrow for locking FLOW to veFLOW
    address public immutable votingEscrow;

    /// @notice The voter contract
    address public immutable voter;

 

    /// -----------------------------------------------------------------------
    /// Storage variables
    /// -----------------------------------------------------------------------


       /// @notice The router for adding liquidity
    address public router; // this should not be immutable

    /// @notice The pair contract that provides the current TWAP price to purchase
    /// the underlying token while exercising options (the strike price)
    IPair public pair;

    /// @notice The guage contract for the pair
    address public gauge;

    /// @notice The treasury address which receives tokens paid during redemption
    address public treasury;

    /// @notice The VM address which receives tokens paid during redemption
    address public vmTreasury;

    /// @notice the discount given during exercising with locking to the LP
    uint256 public  maxLPDiscount = 20; //  User pays 20%
    uint256 public  minLPDiscount = 80; //  User pays 80%

    /// @notice the discount given during exercising. 30 = user pays 30%
    uint256 public discount = 99; // User pays 90%

    /// @notice the discount for locking to veFLOW
    uint256 public veDiscount = 10; // User pays 10%

    /// @notice the lock duration for max discount to create locked LP
    uint256 public lockDurationForMaxLpDiscount = FULL_LOCK; // 52 weeks

    // @notice the lock duration for max discount to create locked LP
    uint256 public lockDurationForMinLpDiscount = 7 * 86400; // 1 week

    /// @notice
    uint256 public teamFee = 5; // 5%

    /// @notice
    uint256 public vmFee = 5; // 5%

    /// @notice controls the duration of the twap used to calculate the strike price
    // each point represents 30 minutes. 4 points = 2 hours
    uint256 public twapPoints = 4;

    /// @notice Is excersizing options currently paused
    bool public isPaused;

    /// -----------------------------------------------------------------------
    /// Modifiers
    /// -----------------------------------------------------------------------
    /// @dev A modifier which checks that the caller has the admin role.
    modifier onlyAdmin() {
        if (!hasRole(ADMIN_ROLE, msg.sender)) revert OptionToken_NoAdminRole();
        _;
    }

    /// @dev A modifier which checks that the caller has the admin role.
    modifier onlyMinter() {
        if (
            !hasRole(ADMIN_ROLE, msg.sender) &&
            !hasRole(MINTER_ROLE, msg.sender)
        ) revert OptionToken_NoMinterRole();
        _;
    }

    /// @dev A modifier which checks that the caller has the pause role.
    modifier onlyPauser() {
        if (!hasRole(PAUSER_ROLE, msg.sender))
            revert OptionToken_NoPauserRole();
        _;
    }

    /// -----------------------------------------------------------------------
    /// Constructor
    /// -----------------------------------------------------------------------

    constructor(
        string memory _name,
        string memory _symbol,
        address _admin,
        address _paymentToken,
        address _underlyingToken,
        IPair _pair,
        address _gaugeFactory,
        address _treasury,
        address _voter,
        address _votingEscrow,
        address _router
    ) ERC20(_name, _symbol, 18) {
        _grantRole(ADMIN_ROLE, _admin);
        _grantRole(PAUSER_ROLE, _admin);
        _grantRole(ADMIN_ROLE, _gaugeFactory);
        _setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE);
        _setRoleAdmin(MINTER_ROLE, ADMIN_ROLE);
        _setRoleAdmin(PAUSER_ROLE, ADMIN_ROLE);
        paymentToken = _paymentToken;
        underlyingToken = _underlyingToken;
        pair = _pair;
        treasury = _treasury;
        vmTreasury = _treasury;
        voter = _voter;
        votingEscrow = _votingEscrow;
        router = _router;

        emit SetPairAndPaymentToken(_pair, paymentToken);
        emit SetTreasury(_treasury,_treasury);
        emit SetRouter(_router);
    }

    /// -----------------------------------------------------------------------
    /// External functions
    /// -----------------------------------------------------------------------

    /// @notice Exercises options tokens to purchase the underlying tokens.
    /// @dev The oracle may revert if it cannot give a secure result.
    /// @param _amount The amount of options tokens to exercise
    /// @param _maxPaymentAmount The maximum acceptable amount to pay. Used for slippage protection.
    /// @param _recipient The recipient of the purchased underlying tokens
    /// @return The amount paid to the treasury to purchase the underlying tokens
    function exercise(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient
    ) external returns (uint256) {
        return _exercise(_amount, _maxPaymentAmount, _recipient);
    }

    /// @notice Exercises options tokens to purchase the underlying tokens.
    /// @dev The oracle may revert if it cannot give a secure result.
    /// @param _amount The amount of options tokens to exercise
    /// @param _maxPaymentAmount The maximum acceptable amount to pay. Used for slippage protection.
    /// @param _recipient The recipient of the purchased underlying tokens
    /// @param _deadline The Unix timestamp (in seconds) after which the call will revert
    /// @return The amount paid to the treasury to purchase the underlying tokens
    function exercise(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient,
        uint256 _deadline
    ) external returns (uint256) {
        if (block.timestamp > _deadline) revert OptionToken_PastDeadline();
        return _exercise(_amount, _maxPaymentAmount, _recipient);
    }

    /// @notice Exercises options tokens to purchase the underlying tokens.
    /// @dev The oracle may revert if it cannot give a secure result.
    /// @param _amount The amount of options tokens to exercise
    /// @param _maxPaymentAmount The maximum acceptable amount to pay. Used for slippage protection.
    /// @param _recipient The recipient of the purchased underlying tokens
    /// @param _deadline The Unix timestamp (in seconds) after which the call will revert
    /// @return The amount paid to the treasury to purchase the underlying tokens
    function exerciseVe(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient,
        uint256 _deadline
    ) external returns (uint256, uint256) {
        if (block.timestamp > _deadline) revert OptionToken_PastDeadline();
        return _exerciseVe(_amount, _maxPaymentAmount, _recipient);
    }

    /// @notice Exercises options tokens to create LP and stake in gauges with lock.
    /// @dev The oracle may revert if it cannot give a secure result.
    /// @param _amount The amount of options tokens to exercise
    /// @param _maxPaymentAmount The maximum acceptable amount to pay. Used for slippage protection.
    /// @param _discount The desired discount
    /// @param _deadline The Unix timestamp (in seconds) after which the call will revert
    /// @return The amount paid to the treasury to purchase the underlying tokens

    function exerciseLp(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient,
        uint256 _discount,
        uint256 _deadline
    ) external returns (uint256, uint256) {
        if (block.timestamp > _deadline) revert OptionToken_PastDeadline();
        return _exerciseLp(_amount, _maxPaymentAmount, _recipient, _discount);
    }

    /// -----------------------------------------------------------------------
    /// Public functions
    /// -----------------------------------------------------------------------

    /// @notice Returns the discounted price in paymentTokens for a given amount of options tokens
    /// @param _amount The amount of options tokens to exercise
    /// @return The amount of payment tokens to pay to purchase the underlying tokens
    function getDiscountedPrice(uint256 _amount) public view returns (uint256) {
        return (getTimeWeightedAveragePrice(_amount) * discount) / 100;
    }

    /// @notice Returns the discounted price in paymentTokens for a given amount of options tokens redeemed to veFLOW
    /// @param _amount The amount of options tokens to exercise
    /// @return The amount of payment tokens to pay to purchase the underlying tokens
    function getVeDiscountedPrice(
        uint256 _amount
    ) public view returns (uint256) {
        return (getTimeWeightedAveragePrice(_amount) * veDiscount) / 100;
    }

    /// @notice Returns the discounted price in paymentTokens for a given amount of options tokens redeemed to veFLOW
    /// @param _amount The amount of options tokens to exercise
    /// @param _discount The discount amount
    /// @return The amount of payment tokens to pay to purchase the underlying tokens
    function getLpDiscountedPrice(
        uint256 _amount,
        uint256 _discount
    ) public view returns (uint256) {
        return (getTimeWeightedAveragePrice(_amount) * _discount) / 100;
    }

    /// @notice Returns the lock duration for a desired discount to create locked LP
    ///
    function getLockDurationForLpDiscount(
        uint256 _discount
    ) public view returns (uint256 duration) {
        (int256 slope, int256 intercept) = getSlopeInterceptForLpDiscount();
        duration = SignedMath.abs(slope * int256(_discount) + intercept);
    }

     // @notice Returns the amount in paymentTokens for a given amount of options tokens required for the LP exercise lp
    /// @param _amount The amount of options tokens to exercise
    /// @param _discount The discount amount
    function getPaymentTokenAmountForExerciseLp(uint256 _amount,uint256 _discount) public view returns (uint256 paymentAmount, uint256 paymentAmountToAddLiquidity)
    {
        paymentAmount = getLpDiscountedPrice(_amount, _discount);
        (uint256 underlyingReserve, uint256 paymentReserve) = IRouter(router).getReserves(underlyingToken, paymentToken, false);
        paymentAmountToAddLiquidity = (_amount * paymentReserve) / underlyingReserve;
    }

    function getSlopeInterceptForLpDiscount()
        public
        view
        returns (int256 slope, int256 intercept)
    {
        slope =
            int256(lockDurationForMaxLpDiscount - lockDurationForMinLpDiscount) /
            (int256(maxLPDiscount) - int256(minLPDiscount));
        intercept = int256(lockDurationForMinLpDiscount) - (slope * int256(minLPDiscount));
    }

    /// @notice Returns the average price in payment tokens over 2 hours for a given amount of underlying tokens
    /// @param _amount The amount of underlying tokens to purchase
    /// @return The amount of payment tokens
    function getTimeWeightedAveragePrice(
        uint256 _amount
    ) public view returns (uint256) {
        uint256[] memory amtsOut = IPair(pair).prices(
            underlyingToken,
            _amount,
            twapPoints
        );
        uint256 len = amtsOut.length;
        uint256 summedAmount;

        for (uint256 i = 0; i < len; i++) {
            summedAmount += amtsOut[i];
        }

        return summedAmount / twapPoints;
    }

    /// -----------------------------------------------------------------------
    /// Admin functions
    /// -----------------------------------------------------------------------

    /// @notice Sets the pair contract. Only callable by the admin.
    /// @param _pair The new pair contract
    function setPairAndPaymentToken(
        IPair _pair,
        address _paymentToken
    ) external onlyAdmin {
        (address token0, address token1) = _pair.tokens();
        if (
            !((token0 == _paymentToken && token1 == underlyingToken) ||
                (token0 == underlyingToken && token1 == _paymentToken))
        ) revert OptionToken_IncorrectPairToken();
        pair = _pair;
        gauge = IVoter(voter).gauges(address(_pair));
        paymentToken = _paymentToken;
        emit SetPairAndPaymentToken(_pair, _paymentToken);
    }

    /// @notice Update gauge address to match with Voter contract
    function updateGauge() external {
        address newGauge = IVoter(voter).gauges(address(pair));
        gauge = newGauge;
        emit SetGauge(newGauge);
    }

    /// @notice Sets the gauge address when the gauge is not listed in Voter. Only callable by the admin.
    /// @param _gauge The new treasury address
    function setGauge(address _gauge) external onlyAdmin {
        gauge = _gauge;
        emit SetGauge(_gauge);
    }

    /// @notice Sets the treasury address. Only callable by the admin.
    /// @param _treasury The new treasury address
    function setTreasury(address _treasury,address _vmTreasury) external onlyAdmin {
        treasury = _treasury;
        vmTreasury = _vmTreasury;
        emit SetTreasury(_treasury,_vmTreasury);
    }

    /// @notice Sets the router address. Only callable by the admin.
    /// @param _router The new router address
    function setRouter(address _router) external onlyAdmin {
        router = _router;
        emit SetRouter(_router);
    }

    /// @notice Sets the team fee. Only callable by the admin.
    /// @param _fee The new team fee.
    /// @param _vmFee The new vm fee.
    function setFees(uint256 _fee,uint256 _vmFee) external onlyAdmin {
        if (_fee + _vmFee > MAX_FEES) revert OptionToken_InvalidFee();
        teamFee = _fee;
        vmFee = _vmFee;
        emit SetFees(_fee,_vmFee);
    }


    /// @notice Sets the discount amount. Only callable by the admin.
    /// @param _discount The new discount amount.
    function setDiscount(uint256 _discount) external onlyAdmin {
        if (_discount > MAX_DISCOUNT || _discount == MIN_DISCOUNT)
            revert OptionToken_InvalidDiscount();
        discount = _discount;
        emit SetDiscount(_discount);
    }

    /// @notice Sets the discount amount for locking. Only callable by the admin.
    /// @param _veDiscount The new discount amount.
    function setVeDiscount(uint256 _veDiscount) external onlyAdmin {
        if (_veDiscount > MAX_DISCOUNT || _veDiscount == MIN_DISCOUNT)
            revert OptionToken_InvalidDiscount();
        veDiscount = _veDiscount;
        emit SetVeDiscount(_veDiscount);
    }

    /// @notice Sets the discount amount for lp. Only callable by the admin.
    /// @param _lpMinDiscount The new discount amount.
    function setMinLPDiscount(uint256 _lpMinDiscount) external onlyAdmin {
        if (_lpMinDiscount > MAX_DISCOUNT || _lpMinDiscount == MIN_DISCOUNT || maxLPDiscount > _lpMinDiscount)
            revert OptionToken_InvalidDiscount();
        minLPDiscount = _lpMinDiscount;
        emit SetMinLPDiscount(_lpMinDiscount);
    }

    /// @notice Sets the discount amount for lp. Only callable by the admin.
    /// @param _lpMaxDiscount The new discount amount.
    function setMaxLPDiscount(uint256 _lpMaxDiscount) external onlyAdmin {
        if (_lpMaxDiscount > MAX_DISCOUNT || _lpMaxDiscount == MIN_DISCOUNT || _lpMaxDiscount > minLPDiscount)
            revert OptionToken_InvalidDiscount();
        maxLPDiscount = _lpMaxDiscount;
        emit SetMaxLPDiscount(_lpMaxDiscount);
    }

    /// @notice Sets the lock duration for max discount amount to create LP and stake in gauge. Only callable by the admin.
    /// @param _duration The new lock duration.
    function setLockDurationForMaxLpDiscount(
        uint256 _duration
    ) external onlyAdmin {
        if (_duration <= lockDurationForMinLpDiscount)
            revert OptionToken_InvalidLockDuration();
        lockDurationForMaxLpDiscount = _duration;
        emit SetLockDurationForMaxLpDiscount(_duration);
    }

    // @notice Sets the lock duration for min discount amount to create LP and stake in gauge. Only callable by the admin.
    /// @param _duration The new lock duration.
    function setLockDurationForMinLpDiscount(
        uint256 _duration
    ) external onlyAdmin {
        if (_duration > lockDurationForMaxLpDiscount)
            revert OptionToken_InvalidLockDuration();
        lockDurationForMinLpDiscount = _duration;
        emit SetLockDurationForMinLpDiscount(_duration);
    }

    /// @notice Sets the twap points. to control the length of our twap
    /// @param _twapPoints The new twap points.
    function setTwapPoints(uint256 _twapPoints) external onlyAdmin {
        if (_twapPoints > MAX_TWAP_POINTS || _twapPoints == 0)
            revert OptionToken_InvalidTwapPoints();
        twapPoints = _twapPoints;
        emit SetTwapPoints(_twapPoints);
    }

    /// @notice Called by the admin to mint options tokens. Admin must grant token approval.
    /// @param _to The address that will receive the minted options tokens
    /// @param _amount The amount of options tokens that will be minted
    function mint(address _to, uint256 _amount) external onlyMinter {
        // transfer underlying tokens from the caller
        _safeTransferFrom(underlyingToken, msg.sender, address(this), _amount);
        // mint options tokens
        _mint(_to, _amount);
    }

    /// @notice Called by the admin to burn options tokens and transfer underlying tokens to the caller.
    /// @param _amount The amount of options tokens that will be burned and underlying tokens transferred to the caller
    function burn(uint256 _amount) external onlyAdmin {
        // transfer underlying tokens to the caller
        _safeTransfer(underlyingToken, msg.sender, _amount);
        // burn option tokens
        _burn(msg.sender, _amount);
    }

    /// @notice called by the admin to re-enable option exercising from a paused state.
    function unPause() external onlyAdmin {
        if (!isPaused) return;
        isPaused = false;
        emit PauseStateChanged(false);
    }

    /// -----------------------------------------------------------------------
    /// Pauser functions
    /// -----------------------------------------------------------------------
    function pause() external onlyPauser {
        if (isPaused) return;
        isPaused = true;
        emit PauseStateChanged(true);
    }

    /// -----------------------------------------------------------------------
    /// Internal functions
    /// -----------------------------------------------------------------------

    function _exercise(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient
    ) internal returns (uint256 paymentAmount) {
        if (isPaused) revert OptionToken_Paused();

        // burn callers tokens
        _burn(msg.sender, _amount);
        paymentAmount = getDiscountedPrice(_amount);
        if (paymentAmount > _maxPaymentAmount)
            revert OptionToken_SlippageTooHigh();

        // transfer team fee to treasury and notify reward amount in gauge
        uint256 gaugeRewardAmount = _takeFees(paymentToken, paymentAmount);
        _usePaymentAsGaugeReward(gaugeRewardAmount);

        // send underlying tokens to recipient
        _safeTransfer(underlyingToken, _recipient, _amount);

        emit Exercise(msg.sender, _recipient, _amount, paymentAmount);
    }

    function _exerciseVe(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient
    ) internal returns (uint256 paymentAmount, uint256 nftId) {
        if (isPaused) revert OptionToken_Paused();

        // burn callers tokens
        _burn(msg.sender, _amount);
        paymentAmount = getVeDiscountedPrice(_amount);
        if (paymentAmount > _maxPaymentAmount)
            revert OptionToken_SlippageTooHigh();

        // transfer team fee to treasury and notify reward amount in gauge
        uint256 gaugeRewardAmount = _takeFees(paymentToken, paymentAmount);
        _usePaymentAsGaugeReward(gaugeRewardAmount);

        // lock underlying tokens to veFLOW
        _safeApprove(underlyingToken, votingEscrow, _amount);
        nftId = IVotingEscrow(votingEscrow).create_lock_for(
            _amount,
            FULL_LOCK,
            _recipient
        );

        emit ExerciseVe(msg.sender, _recipient, _amount, paymentAmount, nftId);
    }

    function _exerciseLp(
        uint256 _amount,   // the oTOKEN amount the user wants to redeem with
        uint256 _maxPaymentAmount, // the 
        address _recipient,
        uint256 _discount
    ) internal returns (uint256 paymentAmount, uint256 lpAmount) {
        if (isPaused) revert OptionToken_Paused();
        if (_discount > minLPDiscount || _discount < maxLPDiscount)
            revert OptionToken_InvalidDiscount();

        // burn callers tokens
        _burn(msg.sender, _amount);
        (uint256 paymentAmount,uint256 paymentAmountToAddLiquidity) =  getPaymentTokenAmountForExerciseLp(_amount,_discount);
        if (paymentAmount > _maxPaymentAmount)
            revert OptionToken_SlippageTooHigh();
          
        // Take team fee
        uint256 paymentGaugeRewardAmount = _takeFees(
            paymentToken,
            paymentAmount
        );
        _safeTransferFrom(
            paymentToken,
            msg.sender,
            address(this),
            paymentGaugeRewardAmount + paymentAmountToAddLiquidity
        );

        // Create Lp for users
        _safeApprove(underlyingToken, router, _amount);
        _safeApprove(paymentToken, router, paymentAmountToAddLiquidity);
        (, , lpAmount) = IRouter(router).addLiquidity(
            underlyingToken,
            paymentToken,
            false,
            _amount,
            paymentAmountToAddLiquidity,
            1,
            1,
            address(this),
            block.timestamp
        );

        // Stake the LP in the gauge with lock
        address _gauge = gauge;
        _safeApprove(address(pair), _gauge, lpAmount);
        IGaugeV2(_gauge).depositWithLock(
            _recipient,
            lpAmount,
            getLockDurationForLpDiscount(_discount)
        );

        // notify gauge reward with payment token
        _transferRewardToGauge();

        emit ExerciseLp(
            msg.sender,
            _recipient,
            _amount,
            paymentAmount,
            lpAmount
        );
    }

    function _takeFees(
        address token,
        uint256 paymentAmount
    ) internal returns (uint256 remaining) {
        uint256 _teamFee = (paymentAmount * teamFee) / 100;
        uint256 _vmFee = (paymentAmount * vmFee) / 100;
        _safeTransferFrom(token, msg.sender, treasury, _teamFee);
        _safeTransferFrom(token, msg.sender, vmTreasury, _vmFee);
        remaining = paymentAmount - _teamFee - _vmFee;
    }

    function _usePaymentAsGaugeReward(uint256 amount) internal {
        _safeTransferFrom(paymentToken, msg.sender, address(this), amount);
        _transferRewardToGauge();
    }

    function _transferRewardToGauge() internal {
        uint256 paymentTokenCollectedAmount = IERC20(paymentToken).balanceOf(address(this));

        uint256 leftRewards = IGaugeV2(gauge).left(paymentToken);

        if(paymentTokenCollectedAmount > leftRewards) { // we are sending rewards only if we have more then the current rewards in the gauge
            _safeApprove(paymentToken, gauge, paymentTokenCollectedAmount);
            IGaugeV2(gauge).notifyRewardAmount(paymentToken, paymentTokenCollectedAmount);
        }
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(IERC20.transfer.selector, to, value)
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(
                IERC20.transferFrom.selector,
                from,
                to,
                value
            )
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeApprove(
        address token,
        address spender,
        uint256 value
    ) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(IERC20.approve.selector, spender, value)
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"contract IPair","name":"_pair","type":"address"},{"internalType":"address","name":"_gaugeFactory","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"_votingEscrow","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OptionToken_IncorrectPairToken","type":"error"},{"inputs":[],"name":"OptionToken_InvalidDiscount","type":"error"},{"inputs":[],"name":"OptionToken_InvalidFee","type":"error"},{"inputs":[],"name":"OptionToken_InvalidLockDuration","type":"error"},{"inputs":[],"name":"OptionToken_InvalidTwapPoints","type":"error"},{"inputs":[],"name":"OptionToken_NoAdminRole","type":"error"},{"inputs":[],"name":"OptionToken_NoMinterRole","type":"error"},{"inputs":[],"name":"OptionToken_NoPauserRole","type":"error"},{"inputs":[],"name":"OptionToken_PastDeadline","type":"error"},{"inputs":[],"name":"OptionToken_Paused","type":"error"},{"inputs":[],"name":"OptionToken_SlippageTooHigh","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"}],"name":"Exercise","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpAmount","type":"uint256"}],"name":"ExerciseLp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"ExerciseVe","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"discount","type":"uint256"}],"name":"SetDiscount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTeamFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVMFee","type":"uint256"}],"name":"SetFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGauge","type":"address"}],"name":"SetGauge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lockDurationForMaxLpDiscount","type":"uint256"}],"name":"SetLockDurationForMaxLpDiscount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lockDurationForMinLpDiscount","type":"uint256"}],"name":"SetLockDurationForMinLpDiscount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lpMaxDiscount","type":"uint256"}],"name":"SetMaxLPDiscount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lpMinDiscount","type":"uint256"}],"name":"SetMinLPDiscount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IPair","name":"newPair","type":"address"},{"indexed":true,"internalType":"address","name":"newPaymentToken","type":"address"}],"name":"SetPairAndPaymentToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRouter","type":"address"}],"name":"SetRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newVMTreasury","type":"address"}],"name":"SetTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"twapPoints","type":"uint256"}],"name":"SetTwapPoints","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"veDiscount","type":"uint256"}],"name":"SetVeDiscount","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":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FULL_LOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DISCOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TWAP_POINTS","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":"MIN_DISCOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","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":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"discount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxPaymentAmount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"exercise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxPaymentAmount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"exercise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxPaymentAmount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_discount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"exerciseLp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxPaymentAmount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"exerciseVe","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getDiscountedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_discount","type":"uint256"}],"name":"getLockDurationForLpDiscount","outputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_discount","type":"uint256"}],"name":"getLpDiscountedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_discount","type":"uint256"}],"name":"getPaymentTokenAmountForExerciseLp","outputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256","name":"paymentAmountToAddLiquidity","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":[],"name":"getSlopeInterceptForLpDiscount","outputs":[{"internalType":"int256","name":"slope","type":"int256"},{"internalType":"int256","name":"intercept","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getTimeWeightedAveragePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getVeDiscountedPrice","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":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDurationForMaxLpDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDurationForMinLpDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLPDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLPDiscount","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":[],"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":"pair","outputs":[{"internalType":"contract IPair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paymentToken","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":"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":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_discount","type":"uint256"}],"name":"setDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_vmFee","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_gauge","type":"address"}],"name":"setGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setLockDurationForMaxLpDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setLockDurationForMinLpDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpMaxDiscount","type":"uint256"}],"name":"setMaxLPDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpMinDiscount","type":"uint256"}],"name":"setMinLPDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPair","name":"_pair","type":"address"},{"internalType":"address","name":"_paymentToken","type":"address"}],"name":"setPairAndPaymentToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_vmTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_twapPoints","type":"uint256"}],"name":"setTwapPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_veDiscount","type":"uint256"}],"name":"setVeDiscount","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":"teamFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"twapPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlyingToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"veDiscount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vmFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vmTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingEscrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6101406040526014600d556050600e556063600f55600a6010556301dfe20060115562093a806012556005601355600560145560046015553480156200004457600080fd5b5060405162003ee938038062003ee98339810160408190526200006791620005d9565b8a8a601282600090805190602001906200008392919062000449565b5081516200009990600190602085019062000449565b5060ff81166080524660a052620000af620002bd565b60c05250620000d2915060008051602062003ec983398151915290508a62000359565b620000fe7f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c8a62000359565b6200011960008051602062003ec98339815191528662000359565b6200013460008051602062003ec983398151915280620003fe565b6200016f7ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc960008051602062003ec9833981519152620003fe565b620001aa7f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c60008051602062003ec9833981519152620003fe565b600780546001600160a01b03808b166001600160a01b0319928316811790935589811660e052600980548a83169084168117909155600b80548984169085168117909155600c80548516909117905586821661012052858216610100526008805492861692909316919091179091556040517f8f7f94e208aee73a455947efb48867081ee05f8c16656f34f471c2fec95b8d6e90600090a36040516001600160a01b0385169081907f190c262dc6f09322c68a13bf67c9659e58367755ba6190fa7ce5ca8aa45a877d90600090a36040516001600160a01b038216907f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e545590600090a25050505050505050505050620007d3565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620002f1919062000730565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60008281526006602090815260408083206001600160a01b038516845290915290205460ff16620003fa5760008281526006602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620003b93390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600082815260066020526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b8280546200045790620006f4565b90600052602060002090601f0160209004810192826200047b5760008555620004c6565b82601f106200049657805160ff1916838001178555620004c6565b82800160010185558215620004c6579182015b82811115620004c6578251825591602001919060010190620004a9565b50620004d4929150620004d8565b5090565b5b80821115620004d45760008155600101620004d9565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200051757600080fd5b81516001600160401b0380821115620005345762000534620004ef565b604051601f8301601f19908116603f011681019082821181831017156200055f576200055f620004ef565b816040528381526020925086838588010111156200057c57600080fd5b600091505b83821015620005a0578582018301518183018401529082019062000581565b83821115620005b25760008385830101525b9695505050505050565b80516001600160a01b0381168114620005d457600080fd5b919050565b60008060008060008060008060008060006101608c8e031215620005fc57600080fd5b8b516001600160401b038111156200061357600080fd5b620006218e828f0162000505565b60208e0151909c5090506001600160401b038111156200064057600080fd5b6200064e8e828f0162000505565b9a50506200065f60408d01620005bc565b98506200066f60608d01620005bc565b97506200067f60808d01620005bc565b96506200068f60a08d01620005bc565b95506200069f60c08d01620005bc565b9450620006af60e08d01620005bc565b9350620006c06101008d01620005bc565b9250620006d16101208d01620005bc565b9150620006e26101408d01620005bc565b90509295989b509295989b9093969950565b600181811c908216806200070957607f821691505b6020821081036200072a57634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806200074d57607f831692505b602080841082036200076d57634e487b7160e01b86526022600452602486fd5b8180156200078457600181146200079657620007c5565b60ff19861689528489019650620007c5565b60008a81526020902060005b86811015620007bd5781548b820152908501908301620007a2565b505084890196505b509498975050505050505050565b60805160a05160c05160e0516101005161012051613644620008856000396000818161065c015281816112110152611e750152600081816106830152818161242f015261248401526000818161054a01528181610fab01528181611016015281816113c401528181611a0801528181611d9601528181611dd20152818161240e015281816125e701528181612734015261279d01526000610e4701526000610e12015260006105b201526136446000f3fe608060405234801561001057600080fd5b506004361061043e5760003560e01c806379c7970711610236578063c7d1e3951161013b578063e3495569116100c3578063f887ea4011610087578063f887ea4014610993578063f897bd1d146109a6578063fa4473b3146109b9578063fb1d6bd9146109cc578063ff26b1c8146109df57600080fd5b8063e349556914610936578063e63ab1e91461093e578063e8772bb214610965578063f595c5ad14610978578063f7b188a51461098b57600080fd5b8063d6379b721161010a578063d6379b72146108c9578063d7c94efd146108dc578063dabd2719146108e5578063dd62ed3e146108f8578063de87db2f1461092357600080fd5b8063c7d1e39514610869578063d505accf1461087c578063d53913931461088f578063d547741f146108b657600080fd5b8063a217fddf116101be578063adfe08701161018d578063adfe08701461082d578063b187bd2614610840578063b34275761461084d578063c0d7865514610856578063c2300bef146107ab57600080fd5b8063a217fddf1461056c578063a6f19c84146107f4578063a8aa1b3114610807578063a9059cbb1461081a57600080fd5b8063881326b311610205578063881326b3146107ab57806391d14854146107b357806395d89b41146107c65780639e66645b146107ce578063a1d50c3a146107e157600080fd5b806379c79707146107725780637ecebe001461077a5780638456cb591461079a578063860ca9bb146107a257600080fd5b80633644e5151161034757806354cb0384116102cf5780636b6f4a9d116102935780636b6f4a9d1461070e5780636e180f6a1461071757806370a082311461072a57806375b238fc1461074a578063787dd9e41461075f57600080fd5b806354cb0384146106c157806355a68ed3146106cc5780635d283021146106df57806361d027b3146106e857806362994c05146106fb57600080fd5b806342966c681161031657806342966c681461064457806346c96aac146106575780634f2bfe5b1461067e57806350a566c5146106a557806351217cbe146106b857600080fd5b80633644e515146105f957806336568abe146106015780633cdfed561461061457806340c10f191461063157600080fd5b806323b872dd116103ca5780632f2ff15d116103995780632f2ff15d146105745780632fc1b057146105875780633013ce291461059a578063313ce567146105ad578063339ccade146105e657600080fd5b806323b872dd1461050f578063248a9ca3146105225780632495a599146105455780632ac8a92c1461056c57600080fd5b8063095ea7b311610411578063095ea7b3146104ac5780630b78f9c0146104bf57806318160ddd146104d25780631adb040a146104db57806320d1b665146104e457600080fd5b806301ffc9a714610443578063062e5bbe1461046b5780630694d1f11461048257806306fdde0314610497575b600080fd5b610456610451366004612db7565b6109e8565b60405190151581526020015b60405180910390f35b610474600d5481565b604051908152602001610462565b610495610490366004612de1565b610a1f565b005b61049f610ab2565b6040516104629190612e2a565b6104566104ba366004612e72565b610b40565b6104956104cd366004612e9e565b610bac565b61047460025481565b61047460115481565b600c546104f7906001600160a01b031681565b6040516001600160a01b039091168152602001610462565b61045661051d366004612ec0565b610c53565b610474610530366004612de1565b60009081526006602052604090206001015490565b6104f77f000000000000000000000000000000000000000000000000000000000000000081565b610474600081565b610495610582366004612f01565b610d33565b610495610595366004612de1565b610d5d565b6007546104f7906001600160a01b031681565b6105d47f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610462565b6104746105f4366004612de1565b610dea565b610474610e0e565b61049561060f366004612f01565b610e69565b61061c610eec565b60408051928352602083019190915201610462565b61049561063f366004612e72565b610f3c565b610495610652366004612de1565b610fdc565b6104f77f000000000000000000000000000000000000000000000000000000000000000081565b6104f77f000000000000000000000000000000000000000000000000000000000000000081565b6104956106b3366004612de1565b611049565b61047460105481565b6104746301dfe20081565b6104956106da366004612f31565b6110ea565b61047460155481565b600b546104f7906001600160a01b031681565b61061c610709366004612f4e565b611169565b610474600f5481565b610474610725366004612de1565b6111a5565b610474610738366004612f31565b60036020526000908152604090205481565b6104746000805160206135cf83398151915281565b61047461076d366004612de1565b6111b5565b6104956111ec565b610474610788366004612f31565b60056020526000908152604090205481565b6104956112ca565b610474600e5481565b610474603281565b6104566107c1366004612f01565b611362565b61049f61138d565b61061c6107dc366004612e9e565b61139a565b6104746107ef366004612f4e565b611473565b600a546104f7906001600160a01b031681565b6009546104f7906001600160a01b031681565b610456610828366004612e72565b6114aa565b61049561083b366004612f8d565b611510565b6016546104569060ff1681565b61047460125481565b610495610864366004612f31565b6115a3565b610474610877366004612e9e565b611622565b61049561088a366004612fbb565b61164b565b6104747ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b6104956108c4366004612f01565b61188f565b6104746108d7366004613032565b6118b4565b61047460135481565b6104956108f3366004612de1565b6118c1565b610474610906366004612f8d565b600460209081526000928352604080842090915290825290205481565b610495610931366004612de1565b611956565b610474606481565b6104747f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c81565b610474610973366004612de1565b6119eb565b610495610986366004612de1565b611aea565b610495611b8b565b6008546104f7906001600160a01b031681565b61061c6109b436600461306b565b611c06565b6104956109c7366004612de1565b611c44565b6104956109da366004612f8d565b611cd9565b61047460145481565b60006001600160e01b03198216637965db0b60e01b1480610a1957506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a376000805160206135cf83398151915233611362565b610a545760405163f982dd0f60e01b815260040160405180910390fd5b6012548111610a7657604051634dd99fe760e01b815260040160405180910390fd5b60118190556040518181527f9604eee1326ca00c5073dfa77c88157865a7db1ed7323c9b1e0bc2aa17fa2ea2906020015b60405180910390a150565b60008054610abf906130b4565b80601f0160208091040260200160405190810160405280929190818152602001828054610aeb906130b4565b8015610b385780601f10610b0d57610100808354040283529160200191610b38565b820191906000526020600020905b815481529060010190602001808311610b1b57829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610b9b9086815260200190565b60405180910390a350600192915050565b610bc46000805160206135cf83398151915233611362565b610be15760405163f982dd0f60e01b815260040160405180910390fd5b6032610bed8284613104565b1115610c0c576040516302ed3d4160e11b815260040160405180910390fd5b6013829055601481905560408051838152602081018390527f3be6e637f54f081a2dd12982cfd58481304fc98b604b18fa8ed4aa4e4a9d1532910160405180910390a15050565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610caf57610c8a838261311c565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610cd790849061311c565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716906000805160206135ef83398151915290610d209087815260200190565b60405180910390a3506001949350505050565b600082815260066020526040902060010154610d4e81611f42565b610d588383611f4c565b505050565b610d756000805160206135cf83398151915233611362565b610d925760405163f982dd0f60e01b815260040160405180910390fd5b601154811115610db557604051634dd99fe760e01b815260040160405180910390fd5b60128190556040518181527f5de612882d01106e49434ea40eed209dc8ad1a1f752a3388f45824f19b07abbb90602001610aa7565b60006064600f54610dfa846119eb565b610e049190613133565b610a199190613168565b60007f00000000000000000000000000000000000000000000000000000000000000004614610e4457610e3f611fd2565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b0381163314610ede5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610ee8828261206c565b5050565b600080600e54600d54610eff919061317c565b601254601154610f0f919061311c565b610f1991906131bb565b9150600e5482610f2991906131e9565b601254610f36919061317c565b90509091565b610f546000805160206135cf83398151915233611362565b158015610f885750610f867ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc933611362565b155b15610fa657604051634fcb6d0160e01b815260040160405180910390fd5b610fd27f00000000000000000000000000000000000000000000000000000000000000003330846120d3565b610ee882826121cb565b610ff46000805160206135cf83398151915233611362565b6110115760405163f982dd0f60e01b815260040160405180910390fd5b61103c7f00000000000000000000000000000000000000000000000000000000000000003383612225565b6110463382612325565b50565b6110616000805160206135cf83398151915233611362565b61107e5760405163f982dd0f60e01b815260040160405180910390fd5b606481118061108b575080155b80611097575080600d54115b156110b5576040516304a5f22d60e41b815260040160405180910390fd5b600e8190556040518181527feccba1be6a56ca0e2c089e59a99f130b3f0bbe23d7bb2d085c278d51b384205890602001610aa7565b6111026000805160206135cf83398151915233611362565b61111f5760405163f982dd0f60e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0383169081179091556040517f17228b08e4c958112a0827a6d8dc8475dba58dd068a3d400800a606794db02a690600090a250565b6000808242111561118d57604051632d56313160e11b815260040160405180910390fd5b611198868686612387565b9150915094509492505050565b60006064601054610dfa846119eb565b60008060006111c2610eec565b90925090506111e4816111d586856131e9565b6111df919061326e565b61254b565b949350505050565b60095460405163b9a09fd560e01b81526001600160a01b0391821660048201526000917f0000000000000000000000000000000000000000000000000000000000000000169063b9a09fd590602401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c91906132af565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250907f17228b08e4c958112a0827a6d8dc8475dba58dd068a3d400800a606794db02a690600090a250565b6112f47f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c33611362565b611311576040516316390a3f60e31b815260040160405180910390fd5b60165460ff16611360576016805460ff191660019081179091556040519081527f4543baa938cb97f5073ec206ad35638cdb1f4db8f677d31579b2f6fe7d18c14a906020015b60405180910390a15b565b60009182526006602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60018054610abf906130b4565b6000806113a78484611622565b600854600754604051635e60dab560e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152918216602482015260006044820181905293955083929190911690635e60dab5906064016040805180830381865afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e91906132cc565b90925090508161145e8288613133565b6114689190613168565b925050509250929050565b60008142111561149657604051632d56313160e11b815260040160405180910390fd5b6114a1858585612562565b95945050505050565b336000908152600360205260408120805483919083906114cb90849061311c565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133906000805160206135ef83398151915290610b9b9086815260200190565b6115286000805160206135cf83398151915233611362565b6115455760405163f982dd0f60e01b815260040160405180910390fd5b600b80546001600160a01b03199081166001600160a01b03858116918217909355600c80549092169284169283179091556040517f190c262dc6f09322c68a13bf67c9659e58367755ba6190fa7ce5ca8aa45a877d90600090a35050565b6115bb6000805160206135cf83398151915233611362565b6115d85760405163f982dd0f60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040517f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e545590600090a250565b6000606482611630856119eb565b61163a9190613133565b6116449190613168565b9392505050565b4284101561169b5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ed5565b600060016116a7610e0e565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156117b3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906117e95750876001600160a01b0316816001600160a01b0316145b6118265760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ed5565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000828152600660205260409020600101546118aa81611f42565b610d58838361206c565b60006111e4848484612562565b6118d96000805160206135cf83398151915233611362565b6118f65760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611903575080155b15611921576040516304a5f22d60e41b815260040160405180910390fd5b600f8190556040518181527ff247e4dd947ab13ba6c46412e403447a26e67109ba13945a20e3170e9acef88390602001610aa7565b61196e6000805160206135cf83398151915233611362565b61198b5760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611998575080155b156119b6576040516304a5f22d60e41b815260040160405180910390fd5b60108190556040518181527f88bde7c07a2800f63dadeaab0c0dca2f3792c92736de0f8e6f89954bb0f3c7df90602001610aa7565b600954601554604051635881c47560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201859052604482019290925260009283921690635881c47590606401600060405180830381865afa158015611a6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a929190810190613306565b80519091506000805b82811015611adc57838181518110611ab557611ab56133c4565b602002602001015182611ac89190613104565b915080611ad4816133da565b915050611a9b565b506015546114a19082613168565b611b026000805160206135cf83398151915233611362565b611b1f5760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611b2c575080155b80611b385750600e5481115b15611b56576040516304a5f22d60e41b815260040160405180910390fd5b600d8190556040518181527f09734b71a2b91b11a979f46fe8751cc0a22e29af3006d1ba5196a7ace08798b490602001610aa7565b611ba36000805160206135cf83398151915233611362565b611bc05760405163f982dd0f60e01b815260040160405180910390fd5b60165460ff1615611360576016805460ff19169055604051600081527f4543baa938cb97f5073ec206ad35638cdb1f4db8f677d31579b2f6fe7d18c14a90602001611357565b60008082421115611c2a57604051632d56313160e11b815260040160405180910390fd5b611c368787878761265b565b915091509550959350505050565b611c5c6000805160206135cf83398151915233611362565b611c795760405163f982dd0f60e01b815260040160405180910390fd5b6032811180611c86575080155b15611ca457604051630ac0408560e01b815260040160405180910390fd5b60158190556040518181527f0ede3419bb2e44475a8c470a557b5e3fa75d2ea0c4a8519c9600579d4091678d90602001610aa7565b611cf16000805160206135cf83398151915233611362565b611d0e5760405163f982dd0f60e01b815260040160405180910390fd5b600080836001600160a01b0316639d63848a6040518163ffffffff1660e01b815260040160408051808303816000875af1158015611d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7491906133f3565b91509150826001600160a01b0316826001600160a01b0316148015611dca57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316145b80611e2257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148015611e225750826001600160a01b0316816001600160a01b0316145b611e3f5760405163a818b0ad60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0386811691821790925560405163b9a09fd560e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000009091169063b9a09fd590602401602060405180830381865afa158015611ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee291906132af565b600a80546001600160a01b039283166001600160a01b0319918216179091556007805486841692168217905560405190918616907f8f7f94e208aee73a455947efb48867081ee05f8c16656f34f471c2fec95b8d6e90600090a350505050565b6110468133612951565b611f568282611362565b610ee85760008281526006602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611f8e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516120049190613422565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6120768282611362565b15610ee85760008281526006602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000846001600160a01b03163b116120ea57600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161214e91906134bd565b6000604051808303816000865af19150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b50915091508180156121ba5750805115806121ba5750808060200190518101906121ba91906134d9565b6121c357600080fd5b505050505050565b80600260008282546121dd9190613104565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481526000805160206135ef83398151915291015b60405180910390a35050565b6000836001600160a01b03163b1161223c57600080fd5b6040516001600160a01b03838116602483015260448201839052600091829186169063a9059cbb60e01b906064015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122a991906134bd565b6000604051808303816000865af19150503d80600081146122e6576040519150601f19603f3d011682016040523d82523d6000602084013e6122eb565b606091505b509150915081801561231557508051158061231557508080602001905181019061231591906134d9565b61231e57600080fd5b5050505050565b6001600160a01b0382166000908152600360205260408120805483929061234d90849061311c565b90915550506002805482900390556040518181526000906001600160a01b038416906000805160206135ef83398151915290602001612219565b601654600090819060ff16156123af5760405162b4aa3760e01b815260040160405180910390fd5b6123b93386612325565b6123c2856111a5565b9150838211156123e5576040516323a4850d60e21b815260040160405180910390fd5b6007546000906123fe906001600160a01b0316846129aa565b905061240981612a31565b6124547f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000088612a51565b60405163d4e54c3b60e01b8152600481018790526301dfe20060248201526001600160a01b0385811660448301527f0000000000000000000000000000000000000000000000000000000000000000169063d4e54c3b906064016020604051808303816000875af11580156124cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f191906134fb565b60408051888152602081018690529081018290529092506001600160a01b0385169033907f74b7132649649ee4ac2519ff0bb963ce812aaa4c8a0ad0f73c9ac1149fa6e3f49060600160405180910390a350935093915050565b60008082121561255e5781600003610a19565b5090565b60165460009060ff16156125885760405162b4aa3760e01b815260040160405180910390fd5b6125923385612325565b61259b84610dea565b9050828111156125be576040516323a4850d60e21b815260040160405180910390fd5b6007546000906125d7906001600160a01b0316836129aa565b90506125e281612a31565b61260d7f00000000000000000000000000000000000000000000000000000000000000008487612225565b60408051868152602081018490526001600160a01b0385169133917fb1c971764663d561c0ec2baf395a55f33f0a79fabb35bbad580247ba2959523d910160405180910390a3509392505050565b601654600090819060ff16156126835760405162b4aa3760e01b815260040160405180910390fd5b600e548311806126945750600d5483105b156126b2576040516304a5f22d60e41b815260040160405180910390fd5b6126bc3387612325565b6000806126c9888661139a565b91509150868211156126ee576040516323a4850d60e21b815260040160405180910390fd5b600754600090612707906001600160a01b0316846129aa565b60075490915061272b906001600160a01b031633306127268686613104565b6120d3565b600854612763907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03168b612a51565b600754600854612780916001600160a01b03908116911684612a51565b600854600754604051635a47ddc360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152918216602482015260006044820152606481018c905260848101859052600160a4820181905260c48201523060e482015242610104820152911690635a47ddc390610124016060604051808303816000875af1158015612827573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284b9190613514565b600a546009549197506001600160a01b03908116935061286e9250168287612a51565b806001600160a01b0316631f933c2d89876128888b6111b5565b6040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b1580156128d657600080fd5b505af11580156128ea573d6000803e3d6000fd5b505050506128f6612a9b565b604080518b8152602081018690529081018690526001600160a01b0389169033907f49a80f92a21531b6bccc1cf51cb96a7f814282e7d6a69d0a4dea0167193cd3589060600160405180910390a35050505094509492505050565b61295b8282611362565b610ee85761296881612c09565b612973836020612c1b565b604051602001612984929190613542565b60408051601f198184030181529082905262461bcd60e51b8252610ed591600401612e2a565b6000806064601354846129bd9190613133565b6129c79190613168565b905060006064601454856129db9190613133565b6129e59190613168565b600b54909150612a0290869033906001600160a01b0316856120d3565b600c54612a1c90869033906001600160a01b0316846120d3565b80612a27838661311c565b6114a1919061311c565b600754612a49906001600160a01b03163330846120d3565b611046612a9b565b6000836001600160a01b03163b11612a6857600080fd5b6040516001600160a01b03838116602483015260448201839052600091829186169063095ea7b360e01b9060640161226b565b6007546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b0891906134fb565b600a54600754604051634cde602960e11b81526001600160a01b0391821660048201529293506000929116906399bcc05290602401602060405180830381865afa158015612b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b7e91906134fb565b905080821115610ee857600754600a54612ba5916001600160a01b03908116911684612a51565b600a5460075460405163b66503cf60e01b81526001600160a01b0391821660048201526024810185905291169063b66503cf90604401600060405180830381600087803b158015612bf557600080fd5b505af11580156121c3573d6000803e3d6000fd5b6060610a196001600160a01b03831660145b60606000612c2a836002613133565b612c35906002613104565b67ffffffffffffffff811115612c4d57612c4d6132f0565b6040519080825280601f01601f191660200182016040528015612c77576020820181803683370190505b509050600360fc1b81600081518110612c9257612c926133c4565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612cc157612cc16133c4565b60200101906001600160f81b031916908160001a9053506000612ce5846002613133565b612cf0906001613104565b90505b6001811115612d68576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612d2457612d246133c4565b1a60f81b828281518110612d3a57612d3a6133c4565b60200101906001600160f81b031916908160001a90535060049490941c93612d61816135b7565b9050612cf3565b5083156116445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ed5565b600060208284031215612dc957600080fd5b81356001600160e01b03198116811461164457600080fd5b600060208284031215612df357600080fd5b5035919050565b60005b83811015612e15578181015183820152602001612dfd565b83811115612e24576000848401525b50505050565b6020815260008251806020840152612e49816040850160208701612dfa565b601f01601f19169190910160400192915050565b6001600160a01b038116811461104657600080fd5b60008060408385031215612e8557600080fd5b8235612e9081612e5d565b946020939093013593505050565b60008060408385031215612eb157600080fd5b50508035926020909101359150565b600080600060608486031215612ed557600080fd5b8335612ee081612e5d565b92506020840135612ef081612e5d565b929592945050506040919091013590565b60008060408385031215612f1457600080fd5b823591506020830135612f2681612e5d565b809150509250929050565b600060208284031215612f4357600080fd5b813561164481612e5d565b60008060008060808587031215612f6457600080fd5b84359350602085013592506040850135612f7d81612e5d565b9396929550929360600135925050565b60008060408385031215612fa057600080fd5b8235612fab81612e5d565b91506020830135612f2681612e5d565b600080600080600080600060e0888a031215612fd657600080fd5b8735612fe181612e5d565b96506020880135612ff181612e5d565b95506040880135945060608801359350608088013560ff8116811461301557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060006060848603121561304757600080fd5b8335925060208401359150604084013561306081612e5d565b809150509250925092565b600080600080600060a0868803121561308357600080fd5b8535945060208601359350604086013561309c81612e5d565b94979396509394606081013594506080013592915050565b600181811c908216806130c857607f821691505b6020821081036130e857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115613117576131176130ee565b500190565b60008282101561312e5761312e6130ee565b500390565b600081600019048311821515161561314d5761314d6130ee565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261317757613177613152565b500490565b60008083128015600160ff1b85018412161561319a5761319a6130ee565b6001600160ff1b03840183138116156131b5576131b56130ee565b50500390565b6000826131ca576131ca613152565b600160ff1b8214600019841416156131e4576131e46130ee565b500590565b60006001600160ff1b038184138284138082168684048611161561320f5761320f6130ee565b600160ff1b600087128281168783058912161561322e5761322e6130ee565b6000871292508782058712848416161561324a5761324a6130ee565b87850587128184161615613260576132606130ee565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615613290576132906130ee565b600160ff1b83900384128116156132a9576132a96130ee565b50500190565b6000602082840312156132c157600080fd5b815161164481612e5d565b600080604083850312156132df57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561331957600080fd5b825167ffffffffffffffff8082111561333157600080fd5b818501915085601f83011261334557600080fd5b815181811115613357576133576132f0565b8060051b604051601f19603f8301168101818110858211171561337c5761337c6132f0565b60405291825284820192508381018501918883111561339a57600080fd5b938501935b828510156133b85784518452938501939285019261339f565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016133ec576133ec6130ee565b5060010190565b6000806040838503121561340657600080fd5b825161341181612e5d565b6020840151909250612f2681612e5d565b600080835481600182811c91508083168061343e57607f831692505b6020808410820361345d57634e487b7160e01b86526022600452602486fd5b8180156134715760018114613482576134af565b60ff198616895284890196506134af565b60008a81526020902060005b868110156134a75781548b82015290850190830161348e565b505084890196505b509498975050505050505050565b600082516134cf818460208701612dfa565b9190910192915050565b6000602082840312156134eb57600080fd5b8151801515811461164457600080fd5b60006020828403121561350d57600080fd5b5051919050565b60008060006060848603121561352957600080fd5b8351925060208401519150604084015190509250925092565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161357a816017850160208801612dfa565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516135ab816028840160208801612dfa565b01602801949350505050565b6000816135c6576135c66130ee565b50600019019056fedf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207528accec6251ef240dfd11fc0a00ded54525544363f2fe3c1ec4f14d3373a2864736f6c634300080d0033df8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab730000000000000000000000004200000000000000000000000000000000000006000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a00000000000000000000000053713f956a4da3f08b55a390b20657edf9e0897b00000000000000000000000096600b4293da981554805ccbab88b48b4c54faa8000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab73000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a00000000000000000000000091f85d68b413de823684c891db515b0390a02512000000000000000000000000e11b93b61f6291d35c5a2bea0a9ff169080160cf00000000000000000000000000000000000000000000000000000000000000114f7074696f6e20746f206275792042564d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046f42564d00000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061043e5760003560e01c806379c7970711610236578063c7d1e3951161013b578063e3495569116100c3578063f887ea4011610087578063f887ea4014610993578063f897bd1d146109a6578063fa4473b3146109b9578063fb1d6bd9146109cc578063ff26b1c8146109df57600080fd5b8063e349556914610936578063e63ab1e91461093e578063e8772bb214610965578063f595c5ad14610978578063f7b188a51461098b57600080fd5b8063d6379b721161010a578063d6379b72146108c9578063d7c94efd146108dc578063dabd2719146108e5578063dd62ed3e146108f8578063de87db2f1461092357600080fd5b8063c7d1e39514610869578063d505accf1461087c578063d53913931461088f578063d547741f146108b657600080fd5b8063a217fddf116101be578063adfe08701161018d578063adfe08701461082d578063b187bd2614610840578063b34275761461084d578063c0d7865514610856578063c2300bef146107ab57600080fd5b8063a217fddf1461056c578063a6f19c84146107f4578063a8aa1b3114610807578063a9059cbb1461081a57600080fd5b8063881326b311610205578063881326b3146107ab57806391d14854146107b357806395d89b41146107c65780639e66645b146107ce578063a1d50c3a146107e157600080fd5b806379c79707146107725780637ecebe001461077a5780638456cb591461079a578063860ca9bb146107a257600080fd5b80633644e5151161034757806354cb0384116102cf5780636b6f4a9d116102935780636b6f4a9d1461070e5780636e180f6a1461071757806370a082311461072a57806375b238fc1461074a578063787dd9e41461075f57600080fd5b806354cb0384146106c157806355a68ed3146106cc5780635d283021146106df57806361d027b3146106e857806362994c05146106fb57600080fd5b806342966c681161031657806342966c681461064457806346c96aac146106575780634f2bfe5b1461067e57806350a566c5146106a557806351217cbe146106b857600080fd5b80633644e515146105f957806336568abe146106015780633cdfed561461061457806340c10f191461063157600080fd5b806323b872dd116103ca5780632f2ff15d116103995780632f2ff15d146105745780632fc1b057146105875780633013ce291461059a578063313ce567146105ad578063339ccade146105e657600080fd5b806323b872dd1461050f578063248a9ca3146105225780632495a599146105455780632ac8a92c1461056c57600080fd5b8063095ea7b311610411578063095ea7b3146104ac5780630b78f9c0146104bf57806318160ddd146104d25780631adb040a146104db57806320d1b665146104e457600080fd5b806301ffc9a714610443578063062e5bbe1461046b5780630694d1f11461048257806306fdde0314610497575b600080fd5b610456610451366004612db7565b6109e8565b60405190151581526020015b60405180910390f35b610474600d5481565b604051908152602001610462565b610495610490366004612de1565b610a1f565b005b61049f610ab2565b6040516104629190612e2a565b6104566104ba366004612e72565b610b40565b6104956104cd366004612e9e565b610bac565b61047460025481565b61047460115481565b600c546104f7906001600160a01b031681565b6040516001600160a01b039091168152602001610462565b61045661051d366004612ec0565b610c53565b610474610530366004612de1565b60009081526006602052604090206001015490565b6104f77f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a81565b610474600081565b610495610582366004612f01565b610d33565b610495610595366004612de1565b610d5d565b6007546104f7906001600160a01b031681565b6105d47f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610462565b6104746105f4366004612de1565b610dea565b610474610e0e565b61049561060f366004612f01565b610e69565b61061c610eec565b60408051928352602083019190915201610462565b61049561063f366004612e72565b610f3c565b610495610652366004612de1565b610fdc565b6104f77f000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a81565b6104f77f00000000000000000000000091f85d68b413de823684c891db515b0390a0251281565b6104956106b3366004612de1565b611049565b61047460105481565b6104746301dfe20081565b6104956106da366004612f31565b6110ea565b61047460155481565b600b546104f7906001600160a01b031681565b61061c610709366004612f4e565b611169565b610474600f5481565b610474610725366004612de1565b6111a5565b610474610738366004612f31565b60036020526000908152604090205481565b6104746000805160206135cf83398151915281565b61047461076d366004612de1565b6111b5565b6104956111ec565b610474610788366004612f31565b60056020526000908152604090205481565b6104956112ca565b610474600e5481565b610474603281565b6104566107c1366004612f01565b611362565b61049f61138d565b61061c6107dc366004612e9e565b61139a565b6104746107ef366004612f4e565b611473565b600a546104f7906001600160a01b031681565b6009546104f7906001600160a01b031681565b610456610828366004612e72565b6114aa565b61049561083b366004612f8d565b611510565b6016546104569060ff1681565b61047460125481565b610495610864366004612f31565b6115a3565b610474610877366004612e9e565b611622565b61049561088a366004612fbb565b61164b565b6104747ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc981565b6104956108c4366004612f01565b61188f565b6104746108d7366004613032565b6118b4565b61047460135481565b6104956108f3366004612de1565b6118c1565b610474610906366004612f8d565b600460209081526000928352604080842090915290825290205481565b610495610931366004612de1565b611956565b610474606481565b6104747f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c81565b610474610973366004612de1565b6119eb565b610495610986366004612de1565b611aea565b610495611b8b565b6008546104f7906001600160a01b031681565b61061c6109b436600461306b565b611c06565b6104956109c7366004612de1565b611c44565b6104956109da366004612f8d565b611cd9565b61047460145481565b60006001600160e01b03198216637965db0b60e01b1480610a1957506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a376000805160206135cf83398151915233611362565b610a545760405163f982dd0f60e01b815260040160405180910390fd5b6012548111610a7657604051634dd99fe760e01b815260040160405180910390fd5b60118190556040518181527f9604eee1326ca00c5073dfa77c88157865a7db1ed7323c9b1e0bc2aa17fa2ea2906020015b60405180910390a150565b60008054610abf906130b4565b80601f0160208091040260200160405190810160405280929190818152602001828054610aeb906130b4565b8015610b385780601f10610b0d57610100808354040283529160200191610b38565b820191906000526020600020905b815481529060010190602001808311610b1b57829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610b9b9086815260200190565b60405180910390a350600192915050565b610bc46000805160206135cf83398151915233611362565b610be15760405163f982dd0f60e01b815260040160405180910390fd5b6032610bed8284613104565b1115610c0c576040516302ed3d4160e11b815260040160405180910390fd5b6013829055601481905560408051838152602081018390527f3be6e637f54f081a2dd12982cfd58481304fc98b604b18fa8ed4aa4e4a9d1532910160405180910390a15050565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610caf57610c8a838261311c565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610cd790849061311c565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716906000805160206135ef83398151915290610d209087815260200190565b60405180910390a3506001949350505050565b600082815260066020526040902060010154610d4e81611f42565b610d588383611f4c565b505050565b610d756000805160206135cf83398151915233611362565b610d925760405163f982dd0f60e01b815260040160405180910390fd5b601154811115610db557604051634dd99fe760e01b815260040160405180910390fd5b60128190556040518181527f5de612882d01106e49434ea40eed209dc8ad1a1f752a3388f45824f19b07abbb90602001610aa7565b60006064600f54610dfa846119eb565b610e049190613133565b610a199190613168565b60007f00000000000000000000000000000000000000000000000000000000000021054614610e4457610e3f611fd2565b905090565b507fa982a9532ec7f200e8e2393fdd9ed99224a74cae71f389c39aaf9715f944151790565b6001600160a01b0381163314610ede5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610ee8828261206c565b5050565b600080600e54600d54610eff919061317c565b601254601154610f0f919061311c565b610f1991906131bb565b9150600e5482610f2991906131e9565b601254610f36919061317c565b90509091565b610f546000805160206135cf83398151915233611362565b158015610f885750610f867ff0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc933611362565b155b15610fa657604051634fcb6d0160e01b815260040160405180910390fd5b610fd27f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a3330846120d3565b610ee882826121cb565b610ff46000805160206135cf83398151915233611362565b6110115760405163f982dd0f60e01b815260040160405180910390fd5b61103c7f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a3383612225565b6110463382612325565b50565b6110616000805160206135cf83398151915233611362565b61107e5760405163f982dd0f60e01b815260040160405180910390fd5b606481118061108b575080155b80611097575080600d54115b156110b5576040516304a5f22d60e41b815260040160405180910390fd5b600e8190556040518181527feccba1be6a56ca0e2c089e59a99f130b3f0bbe23d7bb2d085c278d51b384205890602001610aa7565b6111026000805160206135cf83398151915233611362565b61111f5760405163f982dd0f60e01b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0383169081179091556040517f17228b08e4c958112a0827a6d8dc8475dba58dd068a3d400800a606794db02a690600090a250565b6000808242111561118d57604051632d56313160e11b815260040160405180910390fd5b611198868686612387565b9150915094509492505050565b60006064601054610dfa846119eb565b60008060006111c2610eec565b90925090506111e4816111d586856131e9565b6111df919061326e565b61254b565b949350505050565b60095460405163b9a09fd560e01b81526001600160a01b0391821660048201526000917f000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a169063b9a09fd590602401602060405180830381865afa158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c91906132af565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250907f17228b08e4c958112a0827a6d8dc8475dba58dd068a3d400800a606794db02a690600090a250565b6112f47f539440820030c4994db4e31b6b800deafd503688728f932addfe7a410515c14c33611362565b611311576040516316390a3f60e31b815260040160405180910390fd5b60165460ff16611360576016805460ff191660019081179091556040519081527f4543baa938cb97f5073ec206ad35638cdb1f4db8f677d31579b2f6fe7d18c14a906020015b60405180910390a15b565b60009182526006602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60018054610abf906130b4565b6000806113a78484611622565b600854600754604051635e60dab560e01b81526001600160a01b037f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a81166004830152918216602482015260006044820181905293955083929190911690635e60dab5906064016040805180830381865afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e91906132cc565b90925090508161145e8288613133565b6114689190613168565b925050509250929050565b60008142111561149657604051632d56313160e11b815260040160405180910390fd5b6114a1858585612562565b95945050505050565b336000908152600360205260408120805483919083906114cb90849061311c565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133906000805160206135ef83398151915290610b9b9086815260200190565b6115286000805160206135cf83398151915233611362565b6115455760405163f982dd0f60e01b815260040160405180910390fd5b600b80546001600160a01b03199081166001600160a01b03858116918217909355600c80549092169284169283179091556040517f190c262dc6f09322c68a13bf67c9659e58367755ba6190fa7ce5ca8aa45a877d90600090a35050565b6115bb6000805160206135cf83398151915233611362565b6115d85760405163f982dd0f60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040517f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e545590600090a250565b6000606482611630856119eb565b61163a9190613133565b6116449190613168565b9392505050565b4284101561169b5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ed5565b600060016116a7610e0e565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156117b3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906117e95750876001600160a01b0316816001600160a01b0316145b6118265760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ed5565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000828152600660205260409020600101546118aa81611f42565b610d58838361206c565b60006111e4848484612562565b6118d96000805160206135cf83398151915233611362565b6118f65760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611903575080155b15611921576040516304a5f22d60e41b815260040160405180910390fd5b600f8190556040518181527ff247e4dd947ab13ba6c46412e403447a26e67109ba13945a20e3170e9acef88390602001610aa7565b61196e6000805160206135cf83398151915233611362565b61198b5760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611998575080155b156119b6576040516304a5f22d60e41b815260040160405180910390fd5b60108190556040518181527f88bde7c07a2800f63dadeaab0c0dca2f3792c92736de0f8e6f89954bb0f3c7df90602001610aa7565b600954601554604051635881c47560e01b81526001600160a01b037f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a8116600483015260248201859052604482019290925260009283921690635881c47590606401600060405180830381865afa158015611a6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a929190810190613306565b80519091506000805b82811015611adc57838181518110611ab557611ab56133c4565b602002602001015182611ac89190613104565b915080611ad4816133da565b915050611a9b565b506015546114a19082613168565b611b026000805160206135cf83398151915233611362565b611b1f5760405163f982dd0f60e01b815260040160405180910390fd5b6064811180611b2c575080155b80611b385750600e5481115b15611b56576040516304a5f22d60e41b815260040160405180910390fd5b600d8190556040518181527f09734b71a2b91b11a979f46fe8751cc0a22e29af3006d1ba5196a7ace08798b490602001610aa7565b611ba36000805160206135cf83398151915233611362565b611bc05760405163f982dd0f60e01b815260040160405180910390fd5b60165460ff1615611360576016805460ff19169055604051600081527f4543baa938cb97f5073ec206ad35638cdb1f4db8f677d31579b2f6fe7d18c14a90602001611357565b60008082421115611c2a57604051632d56313160e11b815260040160405180910390fd5b611c368787878761265b565b915091509550959350505050565b611c5c6000805160206135cf83398151915233611362565b611c795760405163f982dd0f60e01b815260040160405180910390fd5b6032811180611c86575080155b15611ca457604051630ac0408560e01b815260040160405180910390fd5b60158190556040518181527f0ede3419bb2e44475a8c470a557b5e3fa75d2ea0c4a8519c9600579d4091678d90602001610aa7565b611cf16000805160206135cf83398151915233611362565b611d0e5760405163f982dd0f60e01b815260040160405180910390fd5b600080836001600160a01b0316639d63848a6040518163ffffffff1660e01b815260040160408051808303816000875af1158015611d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7491906133f3565b91509150826001600160a01b0316826001600160a01b0316148015611dca57507f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a6001600160a01b0316816001600160a01b0316145b80611e2257507f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a6001600160a01b0316826001600160a01b0316148015611e225750826001600160a01b0316816001600160a01b0316145b611e3f5760405163a818b0ad60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0386811691821790925560405163b9a09fd560e01b815260048101919091527f000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a9091169063b9a09fd590602401602060405180830381865afa158015611ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee291906132af565b600a80546001600160a01b039283166001600160a01b0319918216179091556007805486841692168217905560405190918616907f8f7f94e208aee73a455947efb48867081ee05f8c16656f34f471c2fec95b8d6e90600090a350505050565b6110468133612951565b611f568282611362565b610ee85760008281526006602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611f8e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516120049190613422565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6120768282611362565b15610ee85760008281526006602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000846001600160a01b03163b116120ea57600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161214e91906134bd565b6000604051808303816000865af19150503d806000811461218b576040519150601f19603f3d011682016040523d82523d6000602084013e612190565b606091505b50915091508180156121ba5750805115806121ba5750808060200190518101906121ba91906134d9565b6121c357600080fd5b505050505050565b80600260008282546121dd9190613104565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481526000805160206135ef83398151915291015b60405180910390a35050565b6000836001600160a01b03163b1161223c57600080fd5b6040516001600160a01b03838116602483015260448201839052600091829186169063a9059cbb60e01b906064015b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516122a991906134bd565b6000604051808303816000865af19150503d80600081146122e6576040519150601f19603f3d011682016040523d82523d6000602084013e6122eb565b606091505b509150915081801561231557508051158061231557508080602001905181019061231591906134d9565b61231e57600080fd5b5050505050565b6001600160a01b0382166000908152600360205260408120805483929061234d90849061311c565b90915550506002805482900390556040518181526000906001600160a01b038416906000805160206135ef83398151915290602001612219565b601654600090819060ff16156123af5760405162b4aa3760e01b815260040160405180910390fd5b6123b93386612325565b6123c2856111a5565b9150838211156123e5576040516323a4850d60e21b815260040160405180910390fd5b6007546000906123fe906001600160a01b0316846129aa565b905061240981612a31565b6124547f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a7f00000000000000000000000091f85d68b413de823684c891db515b0390a0251288612a51565b60405163d4e54c3b60e01b8152600481018790526301dfe20060248201526001600160a01b0385811660448301527f00000000000000000000000091f85d68b413de823684c891db515b0390a02512169063d4e54c3b906064016020604051808303816000875af11580156124cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f191906134fb565b60408051888152602081018690529081018290529092506001600160a01b0385169033907f74b7132649649ee4ac2519ff0bb963ce812aaa4c8a0ad0f73c9ac1149fa6e3f49060600160405180910390a350935093915050565b60008082121561255e5781600003610a19565b5090565b60165460009060ff16156125885760405162b4aa3760e01b815260040160405180910390fd5b6125923385612325565b61259b84610dea565b9050828111156125be576040516323a4850d60e21b815260040160405180910390fd5b6007546000906125d7906001600160a01b0316836129aa565b90506125e281612a31565b61260d7f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a8487612225565b60408051868152602081018490526001600160a01b0385169133917fb1c971764663d561c0ec2baf395a55f33f0a79fabb35bbad580247ba2959523d910160405180910390a3509392505050565b601654600090819060ff16156126835760405162b4aa3760e01b815260040160405180910390fd5b600e548311806126945750600d5483105b156126b2576040516304a5f22d60e41b815260040160405180910390fd5b6126bc3387612325565b6000806126c9888661139a565b91509150868211156126ee576040516323a4850d60e21b815260040160405180910390fd5b600754600090612707906001600160a01b0316846129aa565b60075490915061272b906001600160a01b031633306127268686613104565b6120d3565b600854612763907f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a906001600160a01b03168b612a51565b600754600854612780916001600160a01b03908116911684612a51565b600854600754604051635a47ddc360e01b81526001600160a01b037f000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a81166004830152918216602482015260006044820152606481018c905260848101859052600160a4820181905260c48201523060e482015242610104820152911690635a47ddc390610124016060604051808303816000875af1158015612827573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284b9190613514565b600a546009549197506001600160a01b03908116935061286e9250168287612a51565b806001600160a01b0316631f933c2d89876128888b6111b5565b6040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b1580156128d657600080fd5b505af11580156128ea573d6000803e3d6000fd5b505050506128f6612a9b565b604080518b8152602081018690529081018690526001600160a01b0389169033907f49a80f92a21531b6bccc1cf51cb96a7f814282e7d6a69d0a4dea0167193cd3589060600160405180910390a35050505094509492505050565b61295b8282611362565b610ee85761296881612c09565b612973836020612c1b565b604051602001612984929190613542565b60408051601f198184030181529082905262461bcd60e51b8252610ed591600401612e2a565b6000806064601354846129bd9190613133565b6129c79190613168565b905060006064601454856129db9190613133565b6129e59190613168565b600b54909150612a0290869033906001600160a01b0316856120d3565b600c54612a1c90869033906001600160a01b0316846120d3565b80612a27838661311c565b6114a1919061311c565b600754612a49906001600160a01b03163330846120d3565b611046612a9b565b6000836001600160a01b03163b11612a6857600080fd5b6040516001600160a01b03838116602483015260448201839052600091829186169063095ea7b360e01b9060640161226b565b6007546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b0891906134fb565b600a54600754604051634cde602960e11b81526001600160a01b0391821660048201529293506000929116906399bcc05290602401602060405180830381865afa158015612b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b7e91906134fb565b905080821115610ee857600754600a54612ba5916001600160a01b03908116911684612a51565b600a5460075460405163b66503cf60e01b81526001600160a01b0391821660048201526024810185905291169063b66503cf90604401600060405180830381600087803b158015612bf557600080fd5b505af11580156121c3573d6000803e3d6000fd5b6060610a196001600160a01b03831660145b60606000612c2a836002613133565b612c35906002613104565b67ffffffffffffffff811115612c4d57612c4d6132f0565b6040519080825280601f01601f191660200182016040528015612c77576020820181803683370190505b509050600360fc1b81600081518110612c9257612c926133c4565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612cc157612cc16133c4565b60200101906001600160f81b031916908160001a9053506000612ce5846002613133565b612cf0906001613104565b90505b6001811115612d68576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612d2457612d246133c4565b1a60f81b828281518110612d3a57612d3a6133c4565b60200101906001600160f81b031916908160001a90535060049490941c93612d61816135b7565b9050612cf3565b5083156116445760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ed5565b600060208284031215612dc957600080fd5b81356001600160e01b03198116811461164457600080fd5b600060208284031215612df357600080fd5b5035919050565b60005b83811015612e15578181015183820152602001612dfd565b83811115612e24576000848401525b50505050565b6020815260008251806020840152612e49816040850160208701612dfa565b601f01601f19169190910160400192915050565b6001600160a01b038116811461104657600080fd5b60008060408385031215612e8557600080fd5b8235612e9081612e5d565b946020939093013593505050565b60008060408385031215612eb157600080fd5b50508035926020909101359150565b600080600060608486031215612ed557600080fd5b8335612ee081612e5d565b92506020840135612ef081612e5d565b929592945050506040919091013590565b60008060408385031215612f1457600080fd5b823591506020830135612f2681612e5d565b809150509250929050565b600060208284031215612f4357600080fd5b813561164481612e5d565b60008060008060808587031215612f6457600080fd5b84359350602085013592506040850135612f7d81612e5d565b9396929550929360600135925050565b60008060408385031215612fa057600080fd5b8235612fab81612e5d565b91506020830135612f2681612e5d565b600080600080600080600060e0888a031215612fd657600080fd5b8735612fe181612e5d565b96506020880135612ff181612e5d565b95506040880135945060608801359350608088013560ff8116811461301557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060006060848603121561304757600080fd5b8335925060208401359150604084013561306081612e5d565b809150509250925092565b600080600080600060a0868803121561308357600080fd5b8535945060208601359350604086013561309c81612e5d565b94979396509394606081013594506080013592915050565b600181811c908216806130c857607f821691505b6020821081036130e857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115613117576131176130ee565b500190565b60008282101561312e5761312e6130ee565b500390565b600081600019048311821515161561314d5761314d6130ee565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261317757613177613152565b500490565b60008083128015600160ff1b85018412161561319a5761319a6130ee565b6001600160ff1b03840183138116156131b5576131b56130ee565b50500390565b6000826131ca576131ca613152565b600160ff1b8214600019841416156131e4576131e46130ee565b500590565b60006001600160ff1b038184138284138082168684048611161561320f5761320f6130ee565b600160ff1b600087128281168783058912161561322e5761322e6130ee565b6000871292508782058712848416161561324a5761324a6130ee565b87850587128184161615613260576132606130ee565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615613290576132906130ee565b600160ff1b83900384128116156132a9576132a96130ee565b50500190565b6000602082840312156132c157600080fd5b815161164481612e5d565b600080604083850312156132df57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561331957600080fd5b825167ffffffffffffffff8082111561333157600080fd5b818501915085601f83011261334557600080fd5b815181811115613357576133576132f0565b8060051b604051601f19603f8301168101818110858211171561337c5761337c6132f0565b60405291825284820192508381018501918883111561339a57600080fd5b938501935b828510156133b85784518452938501939285019261339f565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016133ec576133ec6130ee565b5060010190565b6000806040838503121561340657600080fd5b825161341181612e5d565b6020840151909250612f2681612e5d565b600080835481600182811c91508083168061343e57607f831692505b6020808410820361345d57634e487b7160e01b86526022600452602486fd5b8180156134715760018114613482576134af565b60ff198616895284890196506134af565b60008a81526020902060005b868110156134a75781548b82015290850190830161348e565b505084890196505b509498975050505050505050565b600082516134cf818460208701612dfa565b9190910192915050565b6000602082840312156134eb57600080fd5b8151801515811461164457600080fd5b60006020828403121561350d57600080fd5b5051919050565b60008060006060848603121561352957600080fd5b8351925060208401519150604084015190509250925092565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161357a816017850160208801612dfa565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516135ab816028840160208801612dfa565b01602801949350505050565b6000816135c6576135c66130ee565b50600019019056fedf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212207528accec6251ef240dfd11fc0a00ded54525544363f2fe3c1ec4f14d3373a2864736f6c634300080d0033

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

000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab730000000000000000000000004200000000000000000000000000000000000006000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a00000000000000000000000053713f956a4da3f08b55a390b20657edf9e0897b00000000000000000000000096600b4293da981554805ccbab88b48b4c54faa8000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab73000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a00000000000000000000000091f85d68b413de823684c891db515b0390a02512000000000000000000000000e11b93b61f6291d35c5a2bea0a9ff169080160cf00000000000000000000000000000000000000000000000000000000000000114f7074696f6e20746f206275792042564d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046f42564d00000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Option to buy BVM
Arg [1] : _symbol (string): oBVM
Arg [2] : _admin (address): 0xfA89A4C7F79Dc4111c116a0f01061F4a7D9fAb73
Arg [3] : _paymentToken (address): 0x4200000000000000000000000000000000000006
Arg [4] : _underlyingToken (address): 0xd386a121991E51Eab5e3433Bf5B1cF4C8884b47a
Arg [5] : _pair (address): 0x53713F956A4DA3F08B55A390B20657eDF9E0897B
Arg [6] : _gaugeFactory (address): 0x96600B4293DA981554805cCbAB88B48B4C54fAA8
Arg [7] : _treasury (address): 0xfA89A4C7F79Dc4111c116a0f01061F4a7D9fAb73
Arg [8] : _voter (address): 0xab9B68c9e53c94D7c0949FB909E80e4a29F9134A
Arg [9] : _votingEscrow (address): 0x91F85d68B413dE823684c891db515B0390a02512
Arg [10] : _router (address): 0xE11b93B61f6291d35c5a2beA0A9fF169080160cF

-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [2] : 000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab73
Arg [3] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [4] : 000000000000000000000000d386a121991e51eab5e3433bf5b1cf4c8884b47a
Arg [5] : 00000000000000000000000053713f956a4da3f08b55a390b20657edf9e0897b
Arg [6] : 00000000000000000000000096600b4293da981554805ccbab88b48b4c54faa8
Arg [7] : 000000000000000000000000fa89a4c7f79dc4111c116a0f01061f4a7d9fab73
Arg [8] : 000000000000000000000000ab9b68c9e53c94d7c0949fb909e80e4a29f9134a
Arg [9] : 00000000000000000000000091f85d68b413de823684c891db515b0390a02512
Arg [10] : 000000000000000000000000e11b93b61f6291d35c5a2bea0a9ff169080160cf
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [12] : 4f7074696f6e20746f206275792042564d000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [14] : 6f42564d00000000000000000000000000000000000000000000000000000000


Deployed ByteCode Sourcemap

44062:29012:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25295:204;;;;;;:::i;:::-;;:::i;:::-;;;470:14:1;;463:22;445:41;;433:2;418:18;25295:204:0;;;;;;;;48854:34;;;;;;;;;643:25:1;;;631:2;616:18;48854:34:0;497:177:1;63693:323:0;;;;;;:::i;:::-;;:::i;:::-;;31950:18;;;:::i;:::-;;;;;;;:::i;33427:217::-;;;;;;:::i;:::-;;:::i;61536:231::-;;;;;;:::i;:::-;;:::i;32233:26::-;;;;;;49282:55;;;;;;48743:25;;;;;-1:-1:-1;;;;;48743:25:0;;;;;;-1:-1:-1;;;;;2388:32:1;;;2370:51;;2358:2;2343:18;48743:25:0;2224:203:1;34045:612:0;;;;;;:::i;:::-;;:::i;27118:131::-;;;;;;:::i;:::-;27192:7;27219:12;;;:6;:12;;;;;:22;;;;27118:131;47745:40;;;;;44354;;44393:1;44354:40;;27559:147;;;;;;:::i;:::-;;:::i;64197:322::-;;;;;;:::i;:::-;;:::i;47643:27::-;;;;;-1:-1:-1;;;;;47643:27:0;;;32006:31;;;;;;;;3752:4:1;3740:17;;;3722:36;;3710:2;3695:18;32006:31:0;3580:184:1;56089:156:0;;;;;;:::i;:::-;;:::i;36387:179::-;;;:::i;28703:218::-;;;;;;:::i;:::-;;:::i;58310:390::-;;;:::i;:::-;;;;3939:25:1;;;3995:2;3980:18;;3973:34;;;;3912:18;58310:390:0;3769:244:1;65165:270:0;;;;;;:::i;:::-;;:::i;65670:241::-;;;;;;:::i;:::-;;:::i;47938:30::-;;;;;47856:37;;;;;62711:329;;;;;;:::i;:::-;;:::i;49154:30::-;;;;;;44470:50;;44506:14;44470:50;;60685:118;;;;;;:::i;:::-;;:::i;49764:29::-;;;;;;48634:23;;;;;-1:-1:-1;;;;;48634:23:0;;;54373:336;;;;;;:::i;:::-;;:::i;49048:28::-;;;;;;56524:176;;;;;;:::i;:::-;;:::i;32268:44::-;;;;;;:::i;:::-;;;;;;;;;;;;;;44851:55;;-1:-1:-1;;;;;;;;;;;44851:55:0;;57331:273;;;;;;:::i;:::-;;:::i;60356:166::-;;;:::i;32694:41::-;;;;;;:::i;:::-;;;;;;;;;;;;;;66349:141;;;:::i;48913:34::-;;;;;;44407:44;;44449:2;44407:44;;25591:147;;;;;;:::i;:::-;;:::i;31977:20::-;;;:::i;57845:457::-;;;;;;:::i;:::-;;:::i;53477:323::-;;;;;;:::i;:::-;;:::i;48522:20::-;;;;;-1:-1:-1;;;;;48522:20:0;;;48447:17;;;;;-1:-1:-1;;;;;48447:17:0;;;33652:385;;;;;;:::i;:::-;;:::i;60934:203::-;;;;;;:::i;:::-;;:::i;49859:20::-;;;;;;;;;49429:55;;;;;;61262:124;;;;;;:::i;:::-;;:::i;57025:203::-;;;;;;:::i;:::-;;:::i;34852:1527::-;;;;;;:::i;:::-;;:::i;44995:57::-;;45033:19;44995:57;;27999:149;;;;;;:::i;:::-;;:::i;52686:218::-;;;;;;:::i;:::-;;:::i;49520:26::-;;;;;;61899:255;;;;;;:::i;:::-;;:::i;32321:64::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;62298:271;;;;;;:::i;:::-;;:::i;44297:42::-;;44336:3;44297:42;;45183:57;;45221:19;45183:57;;58936:466;;;;;;:::i;:::-;;:::i;63182:329::-;;;;;;:::i;:::-;;:::i;66008:145::-;;;:::i;48227:21::-;;;;;-1:-1:-1;;;;;48227:21:0;;;55264:375;;;;;;:::i;:::-;;:::i;64649:265::-;;;;;;:::i;:::-;;:::i;59712:569::-;;;;;;:::i;:::-;;:::i;49578:24::-;;;;;;25295:204;25380:4;-1:-1:-1;;;;;;25404:47:0;;-1:-1:-1;;;25404:47:0;;:87;;-1:-1:-1;;;;;;;;;;22710:40:0;;;25455:36;25397:94;25295:204;-1:-1:-1;;25295:204:0:o;63693:323::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;63816:28:::1;;63803:9;:41;63799:100;;63866:33;;-1:-1:-1::0;;;63866:33:0::1;;;;;;;;;;;63799:100;63910:28;:40:::0;;;63966:42:::1;::::0;643:25:1;;;63966:42:0::1;::::0;631:2:1;616:18;63966:42:0::1;;;;;;;;63693:323:::0;:::o;31950:18::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;33427:217::-;33528:10;33501:4;33518:21;;;:9;:21;;;;;;;;-1:-1:-1;;;;;33518:30:0;;;;;;;;;;:39;;;33575:37;33501:4;;33518:30;;33575:37;;;;33551:6;643:25:1;;631:2;616:18;;497:177;33575:37:0;;;;;;;;-1:-1:-1;33632:4:0;33427:217;;;;:::o;61536:231::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44574:2:::1;61616:13;61623:6:::0;61616:4;:13:::1;:::i;:::-;:24;61612:61;;;61649:24;;-1:-1:-1::0;;;61649:24:0::1;;;;;;;;;;;61612:61;61684:7;:14:::0;;;61709:5:::1;:14:::0;;;61739:20:::1;::::0;;3939:25:1;;;3995:2;3980:18;;3973:34;;;61739:20:0::1;::::0;3912:18:1;61739:20:0::1;;;;;;;61536:231:::0;;:::o;34045:612::-;-1:-1:-1;;;;;34202:15:0;;34167:4;34202:15;;;:9;:15;;;;;;;;34218:10;34202:27;;;;;;;;-1:-1:-1;;34282:28:0;;34278:80;;34342:16;34352:6;34342:7;:16;:::i;:::-;-1:-1:-1;;;;;34312:15:0;;;;;;:9;:15;;;;;;;;34328:10;34312:27;;;;;;;:46;34278:80;-1:-1:-1;;;;;34371:15:0;;;;;;:9;:15;;;;;:25;;34390:6;;34371:15;:25;;34390:6;;34371:25;:::i;:::-;;;;-1:-1:-1;;;;;;;34547:13:0;;;;;;;:9;:13;;;;;;;:23;;;;;;34599:26;34547:13;;34599:26;;;-1:-1:-1;;;;;;;;;;;34599:26:0;;;34564:6;643:25:1;;631:2;616:18;;497:177;34599:26:0;;;;;;;;-1:-1:-1;34645:4:0;;34045:612;-1:-1:-1;;;;34045:612:0:o;27559:147::-;27192:7;27219:12;;;:6;:12;;;;;:22;;;25187:16;25198:4;25187:10;:16::i;:::-;27673:25:::1;27684:4;27690:7;27673:10;:25::i;:::-;27559:147:::0;;;:::o;64197:322::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;64319:28:::1;;64307:9;:40;64303:99;;;64369:33;;-1:-1:-1::0;;;64369:33:0::1;;;;;;;;;;;64303:99;64413:28;:40:::0;;;64469:42:::1;::::0;643:25:1;;;64469:42:0::1;::::0;631:2:1;616:18;64469:42:0::1;497:177:1::0;56089:156:0;56155:7;56234:3;56222:8;;56183:36;56211:7;56183:27;:36::i;:::-;:47;;;;:::i;:::-;56182:55;;;;:::i;36387:179::-;36444:7;36488:16;36471:13;:33;:87;;36534:24;:22;:24::i;:::-;36464:94;;36387:179;:::o;36471:87::-;-1:-1:-1;36507:24:0;;36387:179::o;28703:218::-;-1:-1:-1;;;;;28799:23:0;;3787:10;28799:23;28791:83;;;;-1:-1:-1;;;28791:83:0;;9162:2:1;28791:83:0;;;9144:21:1;9201:2;9181:18;;;9174:30;9240:34;9220:18;;;9213:62;-1:-1:-1;;;9291:18:1;;;9284:45;9346:19;;28791:83:0;;;;;;;;;28887:26;28899:4;28905:7;28887:11;:26::i;:::-;28703:218;;:::o;58310:390::-;58400:12;58414:16;58584:13;;58560;;58553:45;;;;:::i;:::-;58507:28;;58476;;:59;;;;:::i;:::-;58469:130;;;;:::i;:::-;58448:151;;58677:13;;58662:5;:29;;;;:::i;:::-;58629:28;;58622:70;;;;:::i;:::-;58610:82;;58310:390;;:::o;65165:270::-;50399:31;-1:-1:-1;;;;;;;;;;;50419:10:0;50399:7;:31::i;:::-;50398:32;:82;;;;;50448:32;45033:19;50469:10;50448:7;:32::i;:::-;50447:33;50398:82;50380:145;;;50499:26;;-1:-1:-1;;;50499:26:0;;;;;;;;;;;50380:145;65295:70:::1;65313:15;65330:10;65350:4;65357:7;65295:17;:70::i;:::-;65408:19;65414:3;65419:7;65408:5;:19::i;65670:241::-:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;65784:51:::1;65798:15;65815:10;65827:7;65784:13;:51::i;:::-;65877:26;65883:10;65895:7;65877:5;:26::i;:::-;65670:241:::0;:::o;62711:329::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44336:3:::1;62795:14;:29;:63;;;-1:-1:-1::0;62828:30:0;;62795:63:::1;:97;;;;62878:14;62862:13;;:30;62795:97;62791:152;;;62914:29;;-1:-1:-1::0;;;62914:29:0::1;;;;;;;;;;;62791:152;62954:13;:30:::0;;;63000:32:::1;::::0;643:25:1;;;63000:32:0::1;::::0;631:2:1;616:18;63000:32:0::1;497:177:1::0;60685:118:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;60749:5:::1;:14:::0;;-1:-1:-1;;;;;;60749:14:0::1;-1:-1:-1::0;;;;;60749:14:0;::::1;::::0;;::::1;::::0;;;60779:16:::1;::::0;::::1;::::0;-1:-1:-1;;60779:16:0::1;60685:118:::0;:::o;54373:336::-;54537:7;54546;54588:9;54570:15;:27;54566:66;;;54606:26;;-1:-1:-1;;;54606:26:0;;;;;;;;;;;54566:66;54650:51;54662:7;54671:17;54690:10;54650:11;:51::i;:::-;54643:58;;;;54373:336;;;;;;;:::o;56524:176::-;56608:7;56689:3;56675:10;;56636:36;56664:7;56636:27;:36::i;57331:273::-;57425:16;57455:12;57469:16;57489:32;:30;:32::i;:::-;57454:67;;-1:-1:-1;57454:67:0;-1:-1:-1;57543:53:0;57454:67;57558:25;57573:9;57454:67;57558:25;:::i;:::-;:37;;;;:::i;:::-;57543:14;:53::i;:::-;57532:64;57331:273;-1:-1:-1;;;;57331:273:0:o;60356:166::-;60447:4;;60418:35;;-1:-1:-1;;;60418:35:0;;-1:-1:-1;;;;;60447:4:0;;;60418:35;;;2370:51:1;60399:16:0;;60425:5;60418:20;;;;2343:18:1;;60418:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60464:5;:16;;-1:-1:-1;;;;;;60464:16:0;-1:-1:-1;;;;;60464:16:0;;;;;;;;60496:18;;60464:16;;-1:-1:-1;60464:16:0;60496:18;;-1:-1:-1;;60496:18:0;60388:134;60356:166::o;66349:141::-;50665:32;45221:19;50686:10;50665:7;:32::i;:::-;50660:85;;50719:26;;-1:-1:-1;;;50719:26:0;;;;;;;;;;;50660:85;66401:8:::1;::::0;::::1;;66411:7;66397:21;66428:8;:15:::0;;-1:-1:-1;;66428:15:0::1;66439:4;66428:15:::0;;::::1;::::0;;;66459:23:::1;::::0;445:41:1;;;66459:23:0::1;::::0;433:2:1;418:18;66459:23:0::1;;;;;;;;50756:1;66349:141::o:0;25591:147::-;25677:4;25701:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;25701:29:0;;;;;;;;;;;;;;;25591:147::o;31977:20::-;;;;;;;:::i;57845:457::-;57945:21;57968:35;58037:40;58058:7;58067:9;58037:20;:40::i;:::-;58150:6;;58187:12;;58142:65;;-1:-1:-1;;;58142:65:0;;-1:-1:-1;;;;;58170:15:0;11182::1;;58142:65:0;;;11164:34:1;58187:12:0;;;11214:18:1;;;11207:43;-1:-1:-1;11266:18:1;;;11259:50;;;58021:56:0;;-1:-1:-1;;;58150:6:0;;;;;58142:27;;11099:18:1;;58142:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;58088:119;;-1:-1:-1;58088:119:0;-1:-1:-1;58088:119:0;58249:24;58088:119;58249:7;:24;:::i;:::-;58248:46;;;;:::i;:::-;58218:76;;58010:292;;57845:457;;;;;:::o;53477:323::-;53639:7;53681:9;53663:15;:27;53659:66;;;53699:26;;-1:-1:-1;;;53699:26:0;;;;;;;;;;;53659:66;53743:49;53753:7;53762:17;53781:10;53743:9;:49::i;:::-;53736:56;53477:323;-1:-1:-1;;;;;53477:323:0:o;33652:385::-;33749:10;33722:4;33739:21;;;:9;:21;;;;;:31;;33764:6;;33739:21;33722:4;;33739:31;;33764:6;;33739:31;:::i;:::-;;;;-1:-1:-1;;;;;;;33921:13:0;;;;;;:9;:13;;;;;;;:23;;;;;;33973:32;33982:10;;-1:-1:-1;;;;;;;;;;;33973:32:0;;;33938:6;643:25:1;;631:2;616:18;;497:177;60934:203:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;61024:8:::1;:20:::0;;-1:-1:-1;;;;;;61024:20:0;;::::1;-1:-1:-1::0;;;;;61024:20:0;;::::1;::::0;;::::1;::::0;;;61055:10:::1;:24:::0;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;61095:34:::1;::::0;::::1;::::0;-1:-1:-1;;61095:34:0::1;60934:203:::0;;:::o;61262:124::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;61328:6:::1;:16:::0;;-1:-1:-1;;;;;;61328:16:0::1;-1:-1:-1::0;;;;;61328:16:0;::::1;::::0;;::::1;::::0;;;61360:18:::1;::::0;::::1;::::0;-1:-1:-1;;61360:18:0::1;61262:124:::0;:::o;57025:203::-;57137:7;57217:3;57204:9;57165:36;57193:7;57165:27;:36::i;:::-;:48;;;;:::i;:::-;57164:56;;;;:::i;:::-;57157:63;57025:203;-1:-1:-1;;;57025:203:0:o;34852:1527::-;35080:15;35068:8;:27;;35060:63;;;;-1:-1:-1;;;35060:63:0;;11772:2:1;35060:63:0;;;11754:21:1;11811:2;11791:18;;;11784:30;11850:25;11830:18;;;11823:53;11893:18;;35060:63:0;11570:347:1;35060:63:0;35293:24;35320:827;35460:18;:16;:18::i;:::-;-1:-1:-1;;;;;35914:13:0;;;;;;;:6;:13;;;;;;;;;:15;;;;;;;;35545:458;;35590:167;35545:458;;;12209:25:1;12288:18;;;12281:43;;;;12360:15;;;12340:18;;;12333:43;12392:18;;;12385:34;;;12435:19;;;12428:35;;;;12479:19;;;;12472:35;;;35545:458:0;;;;;;;;;;12181:19:1;;;35545:458:0;;;35505:525;;;;;;;;-1:-1:-1;;;35380:673:0;;;12776:27:1;12819:11;;;12812:27;;;;12855:12;;;12848:28;;;;12892:12;;35380:673:0;;;-1:-1:-1;;35380:673:0;;;;;;;;;35348:724;;35380:673;35348:724;;;;35320:827;;;;;;;;;13142:25:1;13215:4;13203:17;;13183:18;;;13176:45;13237:18;;;13230:34;;;13280:18;;;13273:34;;;13114:19;;35320:827:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;35320:827:0;;-1:-1:-1;;35320:827:0;;;-1:-1:-1;;;;;;;36172:30:0;;;;;;:59;;;36226:5;-1:-1:-1;;;;;36206:25:0;:16;-1:-1:-1;;;;;36206:25:0;;36172:59;36164:86;;;;-1:-1:-1;;;36164:86:0;;13520:2:1;36164:86:0;;;13502:21:1;13559:2;13539:18;;;13532:30;-1:-1:-1;;;13578:18:1;;;13571:44;13632:18;;36164:86:0;13318:338:1;36164:86:0;-1:-1:-1;;;;;36267:27:0;;;;;;;:9;:27;;;;;;;;:36;;;;;;;;;;;;;:44;;;36340:31;643:25:1;;;36267:36:0;;36340:31;;;;;616:18:1;36340:31:0;;;;;;;34852:1527;;;;;;;:::o;27999:149::-;27192:7;27219:12;;;:6;:12;;;;;:22;;;25187:16;25198:4;25187:10;:16::i;:::-;28114:26:::1;28126:4;28132:7;28114:11;:26::i;52686:218::-:0;52820:7;52847:49;52857:7;52866:17;52885:10;52847:9;:49::i;61899:255::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44336:3:::1;61973:9;:24;:53;;;-1:-1:-1::0;62001:25:0;;61973:53:::1;61969:108;;;62048:29;;-1:-1:-1::0;;;62048:29:0::1;;;;;;;;;;;61969:108;62088:8;:20:::0;;;62124:22:::1;::::0;643:25:1;;;62124:22:0::1;::::0;631:2:1;616:18;62124:22:0::1;497:177:1::0;62298:271:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44336:3:::1;62376:11;:26;:57;;;-1:-1:-1::0;62406:27:0;;62376:57:::1;62372:112;;;62455:29;;-1:-1:-1::0;;;62455:29:0::1;;;;;;;;;;;62372:112;62495:10;:24:::0;;;62535:26:::1;::::0;643:25:1;;;62535:26:0::1;::::0;631:2:1;616:18;62535:26:0::1;497:177:1::0;58936:466:0;59080:4;;59159:10;;59074:106;;-1:-1:-1;;;59074:106:0;;-1:-1:-1;;;;;59107:15:0;13881:32:1;;59074:106:0;;;13863:51:1;13930:18;;;13923:34;;;13973:18;;;13966:34;;;;-1:-1:-1;;;;59080:4:0;;59074:18;;13836::1;;59074:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;59074:106:0;;;;;;;;;;;;:::i;:::-;59205:14;;59047:133;;-1:-1:-1;59191:11:0;;59263:87;59287:3;59283:1;:7;59263:87;;;59328:7;59336:1;59328:10;;;;;;;;:::i;:::-;;;;;;;59312:26;;;;;:::i;:::-;;-1:-1:-1;59292:3:0;;;;:::i;:::-;;;;59263:87;;;-1:-1:-1;59384:10:0;;59369:25;;:12;:25;:::i;63182:329::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44336:3:::1;63266:14;:29;:63;;;-1:-1:-1::0;63299:30:0;;63266:63:::1;:97;;;;63350:13;;63333:14;:30;63266:97;63262:152;;;63385:29;;-1:-1:-1::0;;;63385:29:0::1;;;;;;;;;;;63262:152;63425:13;:30:::0;;;63471:32:::1;::::0;643:25:1;;;63471:32:0::1;::::0;631:2:1;616:18;63471:32:0::1;497:177:1::0;66008:145:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;66062:8:::1;::::0;::::1;;66057:22:::0;66072:7:::1;66057:22;66089:8;:16:::0;;-1:-1:-1;;66089:16:0::1;::::0;;66121:24:::1;::::0;-1:-1:-1;445:41:1;;66121:24:0::1;::::0;433:2:1;418:18;66121:24:0::1;305:187:1::0;55264:375:0;55456:7;55465;55507:9;55489:15;:27;55485:66;;;55525:26;;-1:-1:-1;;;55525:26:0;;;;;;;;;;;55485:66;55569:62;55581:7;55590:17;55609:10;55621:9;55569:11;:62::i;:::-;55562:69;;;;55264:375;;;;;;;;:::o;64649:265::-;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;44449:2:::1;64727:11;:29;:49;;;-1:-1:-1::0;64760:16:0;;64727:49:::1;64723:106;;;64798:31;;-1:-1:-1::0;;;64798:31:0::1;;;;;;;;;;;64723:106;64840:10;:24:::0;;;64880:26:::1;::::0;643:25:1;;;64880:26:0::1;::::0;631:2:1;616:18;64880:26:0::1;497:177:1::0;59712:569:0;50180:31;-1:-1:-1;;;;;;;;;;;50200:10:0;50180:7;:31::i;:::-;50175:70;;50220:25;;-1:-1:-1;;;50220:25:0;;;;;;;;;;;50175:70;59836:14:::1;59852::::0;59870:5:::1;-1:-1:-1::0;;;;;59870:12:0::1;;:14;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59835:49;;;;59926:13;-1:-1:-1::0;;;;;59916:23:0::1;:6;-1:-1:-1::0;;;;;59916:23:0::1;;:52;;;;;59953:15;-1:-1:-1::0;;;;;59943:25:0::1;:6;-1:-1:-1::0;;;;;59943:25:0::1;;59916:52;59915:129;;;;60001:15;-1:-1:-1::0;;;;;59991:25:0::1;:6;-1:-1:-1::0;;;;;59991:25:0::1;;:52;;;;;60030:13;-1:-1:-1::0;;;;;60020:23:0::1;:6;-1:-1:-1::0;;;;;60020:23:0::1;;59991:52;59895:201;;60064:32;;-1:-1:-1::0;;;60064:32:0::1;;;;;;;;;;;59895:201;60107:4;:12:::0;;-1:-1:-1;;;;;;60107:12:0::1;-1:-1:-1::0;;;;;60107:12:0;;::::1;::::0;;::::1;::::0;;;60138:36:::1;::::0;-1:-1:-1;;;60138:36:0;;::::1;::::0;::::1;2370:51:1::0;;;;60145:5:0::1;60138:20:::0;;::::1;::::0;::::1;::::0;2343:18:1;;60138:36:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60130:5;:44:::0;;-1:-1:-1;;;;;60130:44:0;;::::1;-1:-1:-1::0;;;;;;60130:44:0;;::::1;;::::0;;;60185:12:::1;:28:::0;;;;::::1;::::0;::::1;::::0;::::1;::::0;;60229:44:::1;::::0;60185:28;;60229:44;::::1;::::0;::::1;::::0;60130:5:::1;::::0;60229:44:::1;59824:457;;59712:569:::0;;:::o;26042:105::-;26109:30;26120:4;3787:10;26109;:30::i;30300:238::-;30384:22;30392:4;30398:7;30384;:22::i;:::-;30379:152;;30423:12;;;;:6;:12;;;;;;;;-1:-1:-1;;;;;30423:29:0;;;;;;;;;:36;;-1:-1:-1;;30423:36:0;30455:4;30423:36;;;30506:12;3787:10;;3707:98;30506:12;-1:-1:-1;;;;;30479:40:0;30497:7;-1:-1:-1;;;;;30479:40:0;30491:4;30479:40;;;;;;;;;;30300:238;;:::o;36574:457::-;36639:7;36740:95;36874:4;36858:22;;;;;;:::i;:::-;;;;;;;;;;36707:301;;;17412:25:1;;;;17453:18;;17446:34;;;;36903:14:0;17496:18:1;;;17489:34;36940:13:0;17539:18:1;;;17532:34;36984:4:0;17582:19:1;;;17575:61;17384:19;;36707:301:0;;;;;;;;;;;;36679:344;;;;;;36659:364;;36574:457;:::o;30718:239::-;30802:22;30810:4;30816:7;30802;:22::i;:::-;30798:152;;;30873:5;30841:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;30841:29:0;;;;;;;;;;:37;;-1:-1:-1;;30841:37:0;;;30898:40;3787:10;;30841:12;;30898:40;;30873:5;30898:40;30718:239;;:::o;72183:496::-;72357:1;72337:5;-1:-1:-1;;;;;72337:17:0;;:21;72329:30;;;;;;72431:152;;;-1:-1:-1;;;;;17905:15:1;;;72431:152:0;;;17887:34:1;17957:15;;;17937:18;;;17930:43;17989:18;;;;17982:34;;;72431:152:0;;;;;;;;;;17822:18:1;;;;72431:152:0;;;;;;;-1:-1:-1;;;;;72431:152:0;-1:-1:-1;;;72431:152:0;;;72406:188;;-1:-1:-1;;;;72406:10:0;;;;:188;;72431:152;72406:188;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72370:224;;;;72613:7;:57;;;;-1:-1:-1;72625:11:0;;:16;;:44;;;72656:4;72645:24;;;;;;;;;;;;:::i;:::-;72605:66;;;;;;72318:361;;72183:496;;;;:::o;37231:335::-;37317:6;37302:11;;:21;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;37474:13:0;;;;;;:9;:13;;;;;;;;:23;;;;;;37526:32;643:25:1;;;-1:-1:-1;;;;;;;;;;;37526:32:0;616:18:1;37526:32:0;;;;;;;;37231:335;;:::o;71833:342::-;71946:1;71926:5;-1:-1:-1;;;;;71926:17:0;;:21;71918:30;;;;;;72020:59;;-1:-1:-1;;;;;18780:32:1;;;72020:59:0;;;18762:51:1;18829:18;;;18822:34;;;71960:12:0;;;;71995:10;;;-1:-1:-1;;;72043:24:0;18735:18:1;;72020:59:0;;;;-1:-1:-1;;72020:59:0;;;;;;;;;;;;;;-1:-1:-1;;;;;72020:59:0;-1:-1:-1;;;;;;72020:59:0;;;;;;;;;;71995:95;;;;72020:59;71995:95;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71959:131;;;;72109:7;:57;;;;-1:-1:-1;72121:11:0;;:16;;:44;;;72152:4;72141:24;;;;;;;;;;;;:::i;:::-;72101:66;;;;;;71907:268;;71833:342;;;:::o;37574:338::-;-1:-1:-1;;;;;37647:15:0;;;;;;:9;:15;;;;;:25;;37666:6;;37647:15;:25;;37666:6;;37647:25;:::i;:::-;;;;-1:-1:-1;;37820:11:0;:21;;;;;;;37870:34;;643:25:1;;;-1:-1:-1;;;;;;;37870:34:0;;;-1:-1:-1;;;;;;;;;;;37870:34:0;631:2:1;616:18;37870:34:0;497:177:1;67535:1007:0;67725:8;;67672:21;;;;67725:8;;67721:41;;;67742:20;;-1:-1:-1;;;67742:20:0;;;;;;;;;;;67721:41;67807:26;67813:10;67825:7;67807:5;:26::i;:::-;67860:29;67881:7;67860:20;:29::i;:::-;67844:45;;67920:17;67904:13;:33;67900:88;;;67959:29;;-1:-1:-1;;;67959:29:0;;;;;;;;;;;67900:88;68115:12;;68077:25;;68105:38;;-1:-1:-1;;;;;68115:12:0;68129:13;68105:9;:38::i;:::-;68077:66;;68154:43;68179:17;68154:24;:43::i;:::-;68255:52;68268:15;68285:12;68299:7;68255:12;:52::i;:::-;68326:125;;-1:-1:-1;;;68326:125:0;;;;;19069:25:1;;;44506:14:0;19110:18:1;;;19103:34;-1:-1:-1;;;;;19173:32:1;;;19153:18;;;19146:60;68340:12:0;68326:43;;;;19042:18:1;;68326:125:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68469:65;;;19608:25:1;;;19664:2;19649:18;;19642:34;;;19692:18;;;19685:34;;;68318:133:0;;-1:-1:-1;;;;;;68469:65:0;;;68480:10;;68469:65;;19596:2:1;19581:18;68469:65:0;;;;;;;67710:832;67535:1007;;;;;;:::o;18099:218::-;18145:7;18287:1;18282;:6;;:15;;18296:1;18295:2;;18282:15;;;-1:-1:-1;18291:1:0;18099:218::o;66690:837::-;66863:8;;66825:21;;66863:8;;66859:41;;;66880:20;;-1:-1:-1;;;66880:20:0;;;;;;;;;;;66859:41;66945:26;66951:10;66963:7;66945:5;:26::i;:::-;66998:27;67017:7;66998:18;:27::i;:::-;66982:43;;67056:17;67040:13;:33;67036:88;;;67095:29;;-1:-1:-1;;;67095:29:0;;;;;;;;;;;67036:88;67251:12;;67213:25;;67241:38;;-1:-1:-1;;;;;67251:12:0;67265:13;67241:9;:38::i;:::-;67213:66;;67290:43;67315:17;67290:24;:43::i;:::-;67394:51;67408:15;67425:10;67437:7;67394:13;:51::i;:::-;67463:56;;;3939:25:1;;;3995:2;3980:18;;3973:34;;;-1:-1:-1;;;;;67463:56:0;;;67472:10;;67463:56;;3912:18:1;67463:56:0;;;;;;;66848:679;66690:837;;;;;:::o;68550:2099::-;68832:8;;68776:21;;;;68832:8;;68828:41;;;68849:20;;-1:-1:-1;;;68849:20:0;;;;;;;;;;;68828:41;68896:13;;68884:9;:25;:54;;;;68925:13;;68913:9;:25;68884:54;68880:109;;;68960:29;;-1:-1:-1;;;68960:29:0;;;;;;;;;;;68880:109;69034:26;69040:10;69052:7;69034:5;:26::i;:::-;69072:21;69094:35;69134:53;69169:7;69177:9;69134:34;:53::i;:::-;69071:116;;;;69218:17;69202:13;:33;69198:88;;;69257:29;;-1:-1:-1;;;69257:29:0;;;;;;;;;;;69198:88;69394:12;;69335:32;;69370:75;;-1:-1:-1;;;;;69394:12:0;69421:13;69370:9;:75::i;:::-;69488:12;;69335:110;;-1:-1:-1;69456:177:0;;-1:-1:-1;;;;;69488:12:0;69515:10;69548:4;69568:54;69595:27;69335:110;69568:54;:::i;:::-;69456:17;:177::i;:::-;69708:6;;69678:46;;69691:15;;-1:-1:-1;;;;;69708:6:0;69716:7;69678:12;:46::i;:::-;69748:12;;69762:6;;69735:63;;-1:-1:-1;;;;;69748:12:0;;;;69762:6;69770:27;69735:12;:63::i;:::-;69834:6;;69899:12;;69826:270;;-1:-1:-1;;;69826:270:0;;-1:-1:-1;;;;;69869:15:0;20167::1;;69826:270:0;;;20149:34:1;69899:12:0;;;20199:18:1;;;20192:43;-1:-1:-1;20251:18:1;;;20244:50;20310:18;;;20303:34;;;20353:19;;;20346:35;;;69834:6:0;20397:19:1;;;20390:35;;;20441:19;;;20434:35;70050:4:0;20485:19:1;;;20478:44;70070:15:0;20538:19:1;;;20531:35;69834:6:0;;;69826:28;;20083:19:1;;69826:270:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70174:5;;70211:4;;69809:287;;-1:-1:-1;;;;;;70174:5:0;;;;-1:-1:-1;70190:45:0;;-1:-1:-1;70211:4:0;70174:5;69809:287;70190:12;:45::i;:::-;70255:6;-1:-1:-1;;;;;70246:32:0;;70293:10;70318:8;70341:39;70370:9;70341:28;:39::i;:::-;70246:145;;-1:-1:-1;;;;;;70246:145:0;;;;;;;-1:-1:-1;;;;;13881:32:1;;;70246:145:0;;;13863:51:1;13930:18;;;13923:34;;;;13973:18;;;13966:34;13836:18;;70246:145:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70455:24;:22;:24::i;:::-;70497:144;;;19608:25:1;;;19664:2;19649:18;;19642:34;;;19692:18;;;19685:34;;;-1:-1:-1;;;;;70497:144:0;;;70522:10;;70497:144;;19596:2:1;19581:18;70497:144:0;;;;;;;68817:1832;;;;68550:2099;;;;;;;:::o;26437:492::-;26526:22;26534:4;26540:7;26526;:22::i;:::-;26521:401;;26714:28;26734:7;26714:19;:28::i;:::-;26815:38;26843:4;26850:2;26815:19;:38::i;:::-;26619:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;26619:257:0;;;;;;;;;;-1:-1:-1;;;26565:345:0;;;;;;;:::i;70657:435::-;70757:17;70787:16;70834:3;70823:7;;70807:13;:23;;;;:::i;:::-;70806:31;;;;:::i;:::-;70787:50;;70848:14;70891:3;70882:5;;70866:13;:21;;;;:::i;:::-;70865:29;;;;:::i;:::-;70942:8;;70848:46;;-1:-1:-1;70905:56:0;;70923:5;;70930:10;;-1:-1:-1;;;;;70942:8:0;70952;70905:17;:56::i;:::-;71009:10;;70972:56;;70990:5;;70997:10;;-1:-1:-1;;;;;71009:10:0;71021:6;70972:17;:56::i;:::-;71078:6;71051:24;71067:8;71051:13;:24;:::i;:::-;:33;;;;:::i;71100:179::-;71188:12;;71170:66;;-1:-1:-1;;;;;71188:12:0;71202:10;71222:4;71229:6;71170:17;:66::i;:::-;71247:24;:22;:24::i;72687:384::-;72838:1;72818:5;-1:-1:-1;;;;;72818:17:0;;:21;72810:30;;;;;;72912:63;;-1:-1:-1;;;;;18780:32:1;;;72912:63:0;;;18762:51:1;18829:18;;;18822:34;;;72852:12:0;;;;72887:10;;;-1:-1:-1;;;72935:23:0;18735:18:1;;72912:63:0;18588:274:1;71287:538:0;71386:12;;71379:45;;-1:-1:-1;;;71379:45:0;;71418:4;71379:45;;;2370:51:1;71341:35:0;;-1:-1:-1;;;;;71386:12:0;;71379:30;;2343:18:1;;71379:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71468:5;;71480:12;;71459:34;;-1:-1:-1;;;71459:34:0;;-1:-1:-1;;;;;71480:12:0;;;71459:34;;;2370:51:1;71341:83:0;;-1:-1:-1;71437:19:0;;71468:5;;;71459:20;;2343:18:1;;71459:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71437:56;;71539:11;71509:27;:41;71506:312;;;71665:12;;71679:5;;71652:62;;-1:-1:-1;;;;;71665:12:0;;;;71679:5;71686:27;71652:12;:62::i;:::-;71738:5;;71764:12;;71729:77;;-1:-1:-1;;;71729:77:0;;-1:-1:-1;;;;;71764:12:0;;;71729:77;;;18762:51:1;18829:18;;;18822:34;;;71738:5:0;;;71729:34;;18735:18:1;;71729:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20614:151;20672:13;20705:52;-1:-1:-1;;;;;20717:22:0;;18489:2;20010:447;20085:13;20111:19;20143:10;20147:6;20143:1;:10;:::i;:::-;:14;;20156:1;20143:14;:::i;:::-;20133:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;20133:25:0;;20111:47;;-1:-1:-1;;;20169:6:0;20176:1;20169:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;20169:15:0;;;;;;;;;-1:-1:-1;;;20195:6:0;20202:1;20195:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;20195:15:0;;;;;;;;-1:-1:-1;20226:9:0;20238:10;20242:6;20238:1;:10;:::i;:::-;:14;;20251:1;20238:14;:::i;:::-;20226:26;;20221:131;20258:1;20254;:5;20221:131;;;-1:-1:-1;;;20302:5:0;20310:3;20302:11;20293:21;;;;;;;:::i;:::-;;;;20281:6;20288:1;20281:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;20281:33:0;;;;;;;;-1:-1:-1;20339:1:0;20329:11;;;;;20261:3;;;:::i;:::-;;;20221:131;;;-1:-1:-1;20370:10:0;;20362:55;;;;-1:-1:-1;;;20362:55:0;;22022:2:1;20362:55:0;;;22004:21:1;;;22041:18;;;22034:30;22100:34;22080:18;;;22073:62;22152:18;;20362:55:0;21820:356:1;14:286;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:180;738:6;791:2;779:9;770:7;766:23;762:32;759:52;;;807:1;804;797:12;759:52;-1:-1:-1;830:23:1;;679:180;-1:-1:-1;679:180:1:o;864:258::-;936:1;946:113;960:6;957:1;954:13;946:113;;;1036:11;;;1030:18;1017:11;;;1010:39;982:2;975:10;946:113;;;1077:6;1074:1;1071:13;1068:48;;;1112:1;1103:6;1098:3;1094:16;1087:27;1068:48;;864:258;;;:::o;1127:383::-;1276:2;1265:9;1258:21;1239:4;1308:6;1302:13;1351:6;1346:2;1335:9;1331:18;1324:34;1367:66;1426:6;1421:2;1410:9;1406:18;1401:2;1393:6;1389:15;1367:66;:::i;:::-;1494:2;1473:15;-1:-1:-1;;1469:29:1;1454:45;;;;1501:2;1450:54;;1127:383;-1:-1:-1;;1127:383:1:o;1515:131::-;-1:-1:-1;;;;;1590:31:1;;1580:42;;1570:70;;1636:1;1633;1626:12;1651:315;1719:6;1727;1780:2;1768:9;1759:7;1755:23;1751:32;1748:52;;;1796:1;1793;1786:12;1748:52;1835:9;1822:23;1854:31;1879:5;1854:31;:::i;:::-;1904:5;1956:2;1941:18;;;;1928:32;;-1:-1:-1;;;1651:315:1:o;1971:248::-;2039:6;2047;2100:2;2088:9;2079:7;2075:23;2071:32;2068:52;;;2116:1;2113;2106:12;2068:52;-1:-1:-1;;2139:23:1;;;2209:2;2194:18;;;2181:32;;-1:-1:-1;1971:248:1:o;2432:456::-;2509:6;2517;2525;2578:2;2566:9;2557:7;2553:23;2549:32;2546:52;;;2594:1;2591;2584:12;2546:52;2633:9;2620:23;2652:31;2677:5;2652:31;:::i;:::-;2702:5;-1:-1:-1;2759:2:1;2744:18;;2731:32;2772:33;2731:32;2772:33;:::i;:::-;2432:456;;2824:7;;-1:-1:-1;;;2878:2:1;2863:18;;;;2850:32;;2432:456::o;3260:315::-;3328:6;3336;3389:2;3377:9;3368:7;3364:23;3360:32;3357:52;;;3405:1;3402;3395:12;3357:52;3441:9;3428:23;3418:33;;3501:2;3490:9;3486:18;3473:32;3514:31;3539:5;3514:31;:::i;:::-;3564:5;3554:15;;;3260:315;;;;;:::o;4018:247::-;4077:6;4130:2;4118:9;4109:7;4105:23;4101:32;4098:52;;;4146:1;4143;4136:12;4098:52;4185:9;4172:23;4204:31;4229:5;4204:31;:::i;4270:452::-;4356:6;4364;4372;4380;4433:3;4421:9;4412:7;4408:23;4404:33;4401:53;;;4450:1;4447;4440:12;4401:53;4486:9;4473:23;4463:33;;4543:2;4532:9;4528:18;4515:32;4505:42;;4597:2;4586:9;4582:18;4569:32;4610:31;4635:5;4610:31;:::i;:::-;4270:452;;;;-1:-1:-1;4660:5:1;;4712:2;4697:18;4684:32;;-1:-1:-1;;4270:452:1:o;5202:388::-;5270:6;5278;5331:2;5319:9;5310:7;5306:23;5302:32;5299:52;;;5347:1;5344;5337:12;5299:52;5386:9;5373:23;5405:31;5430:5;5405:31;:::i;:::-;5455:5;-1:-1:-1;5512:2:1;5497:18;;5484:32;5525:33;5484:32;5525:33;:::i;5595:829::-;5706:6;5714;5722;5730;5738;5746;5754;5807:3;5795:9;5786:7;5782:23;5778:33;5775:53;;;5824:1;5821;5814:12;5775:53;5863:9;5850:23;5882:31;5907:5;5882:31;:::i;:::-;5932:5;-1:-1:-1;5989:2:1;5974:18;;5961:32;6002:33;5961:32;6002:33;:::i;:::-;6054:7;-1:-1:-1;6108:2:1;6093:18;;6080:32;;-1:-1:-1;6159:2:1;6144:18;;6131:32;;-1:-1:-1;6215:3:1;6200:19;;6187:33;6264:4;6251:18;;6239:31;;6229:59;;6284:1;6281;6274:12;6229:59;5595:829;;;;-1:-1:-1;5595:829:1;;;;6307:7;6361:3;6346:19;;6333:33;;-1:-1:-1;6413:3:1;6398:19;;;6385:33;;5595:829;-1:-1:-1;;5595:829:1:o;6429:383::-;6506:6;6514;6522;6575:2;6563:9;6554:7;6550:23;6546:32;6543:52;;;6591:1;6588;6581:12;6543:52;6627:9;6614:23;6604:33;;6684:2;6673:9;6669:18;6656:32;6646:42;;6738:2;6727:9;6723:18;6710:32;6751:31;6776:5;6751:31;:::i;:::-;6801:5;6791:15;;;6429:383;;;;;:::o;6817:521::-;6912:6;6920;6928;6936;6944;6997:3;6985:9;6976:7;6972:23;6968:33;6965:53;;;7014:1;7011;7004:12;6965:53;7050:9;7037:23;7027:33;;7107:2;7096:9;7092:18;7079:32;7069:42;;7161:2;7150:9;7146:18;7133:32;7174:31;7199:5;7174:31;:::i;:::-;6817:521;;;;-1:-1:-1;7224:5:1;;7276:2;7261:18;;7248:32;;-1:-1:-1;7327:3:1;7312:19;7299:33;;6817:521;-1:-1:-1;;6817:521:1:o;7750:380::-;7829:1;7825:12;;;;7872;;;7893:61;;7947:4;7939:6;7935:17;7925:27;;7893:61;8000:2;7992:6;7989:14;7969:18;7966:38;7963:161;;8046:10;8041:3;8037:20;8034:1;8027:31;8081:4;8078:1;8071:15;8109:4;8106:1;8099:15;7963:161;;7750:380;;;:::o;8135:127::-;8196:10;8191:3;8187:20;8184:1;8177:31;8227:4;8224:1;8217:15;8251:4;8248:1;8241:15;8267:128;8307:3;8338:1;8334:6;8331:1;8328:13;8325:39;;;8344:18;;:::i;:::-;-1:-1:-1;8380:9:1;;8267:128::o;8400:125::-;8440:4;8468:1;8465;8462:8;8459:34;;;8473:18;;:::i;:::-;-1:-1:-1;8510:9:1;;8400:125::o;8530:168::-;8570:7;8636:1;8632;8628:6;8624:14;8621:1;8618:21;8613:1;8606:9;8599:17;8595:45;8592:71;;;8643:18;;:::i;:::-;-1:-1:-1;8683:9:1;;8530:168::o;8703:127::-;8764:10;8759:3;8755:20;8752:1;8745:31;8795:4;8792:1;8785:15;8819:4;8816:1;8809:15;8835:120;8875:1;8901;8891:35;;8906:18;;:::i;:::-;-1:-1:-1;8940:9:1;;8835:120::o;9376:267::-;9415:4;9444:9;;;9469:10;;-1:-1:-1;;;9488:19:1;;9481:27;;9465:44;9462:70;;;9512:18;;:::i;:::-;-1:-1:-1;;;;;9559:27:1;;9552:35;;9544:44;;9541:70;;;9591:18;;:::i;:::-;-1:-1:-1;;9628:9:1;;9376:267::o;9648:193::-;9687:1;9713;9703:35;;9718:18;;:::i;:::-;-1:-1:-1;;;9754:18:1;;-1:-1:-1;;9774:13:1;;9750:38;9747:64;;;9791:18;;:::i;:::-;-1:-1:-1;9825:10:1;;9648:193::o;9846:553::-;9885:7;-1:-1:-1;;;;;9955:9:1;;;9983;;;10008:11;;;10027:10;;;10021:17;;10004:35;10001:61;;;10042:18;;:::i;:::-;-1:-1:-1;;;10118:1:1;10111:9;;10136:11;;;10156;;;10149:19;;10132:37;10129:63;;;10172:18;;:::i;:::-;10218:1;10215;10211:9;10201:19;;10265:1;10261:2;10256:11;10253:1;10249:19;10244:2;10240;10236:11;10232:37;10229:63;;;10272:18;;:::i;:::-;10337:1;10333:2;10328:11;10325:1;10321:19;10316:2;10312;10308:11;10304:37;10301:63;;;10344:18;;:::i;:::-;-1:-1:-1;;;10384:9:1;;;;;9846:553;-1:-1:-1;;;9846:553:1:o;10404:265::-;10443:3;10471:9;;;10496:10;;-1:-1:-1;;;;;10515:27:1;;;10508:35;;10492:52;10489:78;;;10547:18;;:::i;:::-;-1:-1:-1;;;10594:19:1;;;10587:27;;10579:36;;10576:62;;;10618:18;;:::i;:::-;-1:-1:-1;;10654:9:1;;10404:265::o;10674:251::-;10744:6;10797:2;10785:9;10776:7;10772:23;10768:32;10765:52;;;10813:1;10810;10803:12;10765:52;10845:9;10839:16;10864:31;10889:5;10864:31;:::i;11320:245::-;11399:6;11407;11460:2;11448:9;11439:7;11435:23;11431:32;11428:52;;;11476:1;11473;11466:12;11428:52;-1:-1:-1;;11499:16:1;;11555:2;11540:18;;;11534:25;11499:16;;11534:25;;-1:-1:-1;11320:245:1:o;14011:127::-;14072:10;14067:3;14063:20;14060:1;14053:31;14103:4;14100:1;14093:15;14127:4;14124:1;14117:15;14143:1105;14238:6;14269:2;14312;14300:9;14291:7;14287:23;14283:32;14280:52;;;14328:1;14325;14318:12;14280:52;14361:9;14355:16;14390:18;14431:2;14423:6;14420:14;14417:34;;;14447:1;14444;14437:12;14417:34;14485:6;14474:9;14470:22;14460:32;;14530:7;14523:4;14519:2;14515:13;14511:27;14501:55;;14552:1;14549;14542:12;14501:55;14581:2;14575:9;14603:2;14599;14596:10;14593:36;;;14609:18;;:::i;:::-;14655:2;14652:1;14648:10;14687:2;14681:9;14750:2;14746:7;14741:2;14737;14733:11;14729:25;14721:6;14717:38;14805:6;14793:10;14790:22;14785:2;14773:10;14770:18;14767:46;14764:72;;;14816:18;;:::i;:::-;14852:2;14845:22;14902:18;;;14936:15;;;;-1:-1:-1;14978:11:1;;;14974:20;;;15006:19;;;15003:39;;;15038:1;15035;15028:12;15003:39;15062:11;;;;15082:135;15098:6;15093:3;15090:15;15082:135;;;15164:10;;15152:23;;15115:12;;;;15195;;;;15082:135;;;15236:6;14143:1105;-1:-1:-1;;;;;;;;14143:1105:1:o;15253:127::-;15314:10;15309:3;15305:20;15302:1;15295:31;15345:4;15342:1;15335:15;15369:4;15366:1;15359:15;15385:135;15424:3;15445:17;;;15442:43;;15465:18;;:::i;:::-;-1:-1:-1;15512:1:1;15501:13;;15385:135::o;15525:385::-;15604:6;15612;15665:2;15653:9;15644:7;15640:23;15636:32;15633:52;;;15681:1;15678;15671:12;15633:52;15713:9;15707:16;15732:31;15757:5;15732:31;:::i;:::-;15832:2;15817:18;;15811:25;15782:5;;-1:-1:-1;15845:33:1;15811:25;15845:33;:::i;16044:1104::-;16174:3;16203:1;16236:6;16230:13;16266:3;16288:1;16316:9;16312:2;16308:18;16298:28;;16376:2;16365:9;16361:18;16398;16388:61;;16442:4;16434:6;16430:17;16420:27;;16388:61;16468:2;16516;16508:6;16505:14;16485:18;16482:38;16479:165;;-1:-1:-1;;;16543:33:1;;16599:4;16596:1;16589:15;16629:4;16550:3;16617:17;16479:165;16660:18;16687:104;;;;16805:1;16800:323;;;;16653:470;;16687:104;-1:-1:-1;;16720:24:1;;16708:37;;16765:16;;;;-1:-1:-1;16687:104:1;;16800:323;15991:1;15984:14;;;16028:4;16015:18;;16898:1;16912:165;16926:6;16923:1;16920:13;16912:165;;;17004:14;;16991:11;;;16984:35;17047:16;;;;16941:10;;16912:165;;;16916:3;;17106:6;17101:3;17097:16;17090:23;;16653:470;-1:-1:-1;17139:3:1;;16044:1104;-1:-1:-1;;;;;;;;16044:1104:1:o;18027:274::-;18156:3;18194:6;18188:13;18210:53;18256:6;18251:3;18244:4;18236:6;18232:17;18210:53;:::i;:::-;18279:16;;;;;18027:274;-1:-1:-1;;18027:274:1:o;18306:277::-;18373:6;18426:2;18414:9;18405:7;18401:23;18397:32;18394:52;;;18442:1;18439;18432:12;18394:52;18474:9;18468:16;18527:5;18520:13;18513:21;18506:5;18503:32;18493:60;;18549:1;18546;18539:12;19217:184;19287:6;19340:2;19328:9;19319:7;19315:23;19311:32;19308:52;;;19356:1;19353;19346:12;19308:52;-1:-1:-1;19379:16:1;;19217:184;-1:-1:-1;19217:184:1:o;20577:306::-;20665:6;20673;20681;20734:2;20722:9;20713:7;20709:23;20705:32;20702:52;;;20750:1;20747;20740:12;20702:52;20779:9;20773:16;20763:26;;20829:2;20818:9;20814:18;20808:25;20798:35;;20873:2;20862:9;20858:18;20852:25;20842:35;;20577:306;;;;;:::o;20888:786::-;21299:25;21294:3;21287:38;21269:3;21354:6;21348:13;21370:62;21425:6;21420:2;21415:3;21411:12;21404:4;21396:6;21392:17;21370:62;:::i;:::-;-1:-1:-1;;;21491:2:1;21451:16;;;21483:11;;;21476:40;21541:13;;21563:63;21541:13;21612:2;21604:11;;21597:4;21585:17;;21563:63;:::i;:::-;21646:17;21665:2;21642:26;;20888:786;-1:-1:-1;;;;20888:786:1:o;21679:136::-;21718:3;21746:5;21736:39;;21755:18;;:::i;:::-;-1:-1:-1;;;21791:18:1;;21679:136::o

Swarm Source

ipfs://7528accec6251ef240dfd11fc0a00ded54525544363f2fe3c1ec4f14d3373a28
Loading