ETH Price: $2,346.92 (-0.44%)

Contract

0x567c09B55294998d7a6F2A3A948e8fD331531B88
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Settle Expired187350692023-12-07 14:40:47280 days ago1701960047IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0103903986.755829
Settle Expired187126392023-12-04 11:15:35283 days ago1701688535IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0111829393.37322092
Settle Expired186718412023-11-28 18:15:11288 days ago1701195311IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0139811665.12985001
Expire186709062023-11-28 15:06:23289 days ago1701183983IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0201231356.94281003
Withdraw186550072023-11-26 9:38:59291 days ago1700991539IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0018863322.9654434
Redeem186550012023-11-26 9:37:47291 days ago1700991467IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0024883821.73656304
Repay186496232023-11-25 15:32:23292 days ago1700926343IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0024106429.81221828
Redeem186124372023-11-20 10:35:23297 days ago1700476523IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0027873223.03572746
Redeem185910202023-11-17 10:32:11300 days ago1700217131IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0032394523.75539956
Create185909982023-11-17 10:27:47300 days ago1700216867IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.003115123.73447981
Redeem185286502023-11-08 17:12:47309 days ago1699463567IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0068255856.41441849
Withdraw185279442023-11-08 14:50:35309 days ago1699455035IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0033610840.91996801
Repay185275012023-11-08 13:21:35309 days ago1699449695IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0032931938.80240125
Deposit176918372023-07-14 12:55:59426 days ago1689339359IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0021401526.18630997
Create176289132023-07-05 16:37:23435 days ago1688575043IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0103309663.79543955
Redeem175800792023-06-28 20:04:11441 days ago1687982651IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0024317420.09873451
Withdraw175800712023-06-28 20:02:35441 days ago1687982555IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0016726820.37032397
Create175791532023-06-28 16:57:35442 days ago1687971455IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0046006926.82199744
Create175713212023-06-27 14:36:47443 days ago1687876607IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0024713821.13743361
Create175713112023-06-27 14:34:35443 days ago1687876475IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0037025921.58303058
Create175427742023-06-23 14:10:35447 days ago1687529435IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0029642321.79009024
Create175425452023-06-23 13:24:35447 days ago1687526675IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.003150118.36378425
Redeem175301222023-06-21 19:28:59448 days ago1687375739IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0032843827.92773404
Deposit175093552023-06-18 21:32:35451 days ago1687123955IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0011142413.63152401
Create174735142023-06-13 20:42:11456 days ago1686688931IN
Sumero Finance: cVT Expiring Multi Party
0 ETH0.0017727615.16065317
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
173863452023-06-01 13:46:23469 days ago1685627183  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ExpiringMultiParty

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : ExpiringMultiParty.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Liquidatable.sol";

/**
 * @title Expiring Multi Party.
 * @notice Convenient wrapper for Liquidatable.
 */
contract ExpiringMultiParty is Liquidatable {
    /**
     * @notice Constructs the ExpiringMultiParty contract.
     * @param params struct to define input parameters for construction of Liquidatable. Some params
     * are fed directly into the PricelessPositionManager's constructor within the inheritance tree.
     */
    constructor(ConstructorParams memory params)
        Liquidatable(params)
    // Note: since there is no logic here, there is no need to add a re-entrancy guard.
    {

    }
}

File 2 of 18 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 4 of 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

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

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

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

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

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

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

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

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

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

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

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

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

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

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

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

File 7 of 18 : SignedSafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SignedSafeMath {
    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        return a * b;
    }

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

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

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

File 8 of 18 : FixedPoint.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SignedSafeMath.sol";

/**
 * @title Library for fixed point arithmetic on uints
 */
library FixedPoint {
    using SafeMath for uint256;
    using SignedSafeMath for int256;

    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For unsigned values:
    //   This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.
    uint256 private constant FP_SCALING_FACTOR = 10**18;

    // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------
    struct Unsigned {
        uint256 rawValue;
    }

    /**
     * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a uint to convert into a FixedPoint.
     * @return the converted FixedPoint.
     */
    function fromUnscaledUint(uint256 a)
        internal
        pure
        returns (Unsigned memory)
    {
        return Unsigned(a.mul(FP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, uint256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue == fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, uint256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue > fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(uint256 a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledUint(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, uint256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue >= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(uint256 a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledUint(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, uint256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue < fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(uint256 a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledUint(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, uint256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue <= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(uint256 a, Unsigned memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledUint(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the minimum of `a` and `b`.
     */
    function min(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the maximum of `a` and `b`.
     */
    function max(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return Unsigned(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        return add(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return Unsigned(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        return sub(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(uint256 a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return sub(fromUnscaledUint(a), b);
    }

    /**
     * @notice Multiplies two `Unsigned`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as a uint256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because FP_SCALING_FACTOR != 0.
        return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        uint256 mulRaw = a.rawValue.mul(b.rawValue);
        uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;
        uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);
        if (mod != 0) {
            return Unsigned(mulFloor.add(1));
        } else {
            return Unsigned(mulFloor);
        }
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        // Since b is an uint, there is no risk of truncation and we can just mul it normally
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as a uint256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        return Unsigned(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a uint256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(uint256 a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        return div(fromUnscaledUint(a), b);
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, Unsigned memory b)
        internal
        pure
        returns (Unsigned memory)
    {
        uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);
        uint256 divFloor = aScaled.div(b.rawValue);
        uint256 mod = aScaled.mod(b.rawValue);
        if (mod != 0) {
            return Unsigned(divFloor.add(1));
        } else {
            return Unsigned(divFloor);
        }
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory)
    {
        // Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))"
        // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.
        // This creates the possibility of overflow if b is very large.
        return divCeil(a, fromUnscaledUint(b));
    }

    /**
     * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return output is `a` to the power of `b`.
     */
    function pow(Unsigned memory a, uint256 b)
        internal
        pure
        returns (Unsigned memory output)
    {
        output = fromUnscaledUint(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }

    // ------------------------------------------------- SIGNED -------------------------------------------------------------
    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For signed values:
    //   This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.
    int256 private constant SFP_SCALING_FACTOR = 10**18;

    struct Signed {
        int256 rawValue;
    }

    function fromSigned(Signed memory a)
        internal
        pure
        returns (Unsigned memory)
    {
        require(a.rawValue >= 0, "Negative value provided");
        return Unsigned(uint256(a.rawValue));
    }

    function fromUnsigned(Unsigned memory a)
        internal
        pure
        returns (Signed memory)
    {
        require(a.rawValue <= uint256(type(int256).max), "Unsigned too large");
        return Signed(int256(a.rawValue));
    }

    /**
     * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a int to convert into a FixedPoint.Signed.
     * @return the converted FixedPoint.Signed.
     */
    function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {
        return Signed(a.mul(SFP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a int256.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue == fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, int256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue > fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(int256 a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledInt(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, int256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue >= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(int256 a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledInt(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, int256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue < fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(int256 a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledInt(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, int256 b)
        internal
        pure
        returns (bool)
    {
        return a.rawValue <= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(int256 a, Signed memory b)
        internal
        pure
        returns (bool)
    {
        return fromUnscaledInt(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the minimum of `a` and `b`.
     */
    function min(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the maximum of `a` and `b`.
     */
    function max(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return Signed(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Signed` to an unscaled int, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        return add(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return Signed(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        return sub(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(int256 a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return sub(fromUnscaledInt(a), b);
    }

    /**
     * @notice Multiplies two `Signed`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as an int256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because SFP_SCALING_FACTOR != 0.
        return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        int256 mulRaw = a.rawValue.mul(b.rawValue);
        int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = mulRaw % SFP_SCALING_FACTOR;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(mulTowardsZero.add(valueToAdd));
        } else {
            return Signed(mulTowardsZero);
        }
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        // Since b is an int, there is no risk of truncation and we can just mul it normally
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as an int256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        return Signed(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a an int256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(int256 a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        return div(fromUnscaledInt(a), b);
    }

    /**
     * @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, Signed memory b)
        internal
        pure
        returns (Signed memory)
    {
        int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);
        int256 divTowardsZero = aScaled.div(b.rawValue);
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = aScaled % b.rawValue;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(divTowardsZero.add(valueToAdd));
        } else {
            return Signed(divTowardsZero);
        }
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, int256 b)
        internal
        pure
        returns (Signed memory)
    {
        // Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))"
        // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.
        // This creates the possibility of overflow if b is very large.
        return divAwayFromZero(a, fromUnscaledInt(b));
    }

    /**
     * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint.Signed.
     * @param b a uint256 (negative exponents are not allowed).
     * @return output is `a` to the power of `b`.
     */
    function pow(Signed memory a, uint256 b)
        internal
        pure
        returns (Signed memory output)
    {
        output = fromUnscaledInt(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }
}

File 9 of 18 : Lockable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract
 * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
 * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.
 */
contract Lockable {
    bool private _notEntered;

    constructor() {
        // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every
        // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full
        // refund coming into effect.
        _notEntered = true;
    }

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

    /**
     * @dev Designed to prevent a view-only method from being re-entered during a call to a `nonReentrant()` state-changing method.
     */
    modifier nonReentrantView() {
        _preEntranceCheck();
        _;
    }

    // Internal methods are used to avoid copying the require statement's bytecode to every `nonReentrant()` method.
    // On entry into a function, `_preEntranceCheck()` should always be called to check if the function is being
    // re-entered. Then, if the function modifies state, it should call `_postEntranceSet()`, perform its logic, and
    // then call `_postEntranceReset()`.
    // View-only methods can simply call `_preEntranceCheck()` to make sure that it is not being re-entered.
    function _preEntranceCheck() internal view {
        // On the first call to nonReentrant, _notEntered will be true
        require(_notEntered, "ReentrancyGuard: reentrant call");
    }

    function _preEntranceSet() internal {
        // Any calls to nonReentrant after this point will fail
        _notEntered = false;
    }

    function _postEntranceReset() internal {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _notEntered = true;
    }

    // These functions are intended to be used by child contracts to temporarily disable and re-enable the guard.
    // Intended use:
    // _startReentrantGuardDisabled();
    // ...
    // _endReentrantGuardDisabled();
    //
    // IMPORTANT: these should NEVER be used in a method that isn't inside a nonReentrant block. Otherwise, it's
    // possible to permanently lock your contract.
    function _startReentrantGuardDisabled() internal {
        _notEntered = true;
    }

    function _endReentrantGuardDisabled() internal {
        _notEntered = false;
    }
}

File 10 of 18 : ExpandedIERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/**
 * @title ERC20 interface that includes burn and mint methods.
 */
abstract contract ExpandedIERC20 is IERC20 {
    /**
     * @notice Burns a specific amount of the caller's tokens.
     * @dev Only burns the caller's tokens, so it is safe to leave this method permissionless.
     */
    function burn(uint256 value) external virtual;

    /**
     * @dev Burns `value` tokens owned by `recipient`.
     * @param recipient address to burn tokens from.
     * @param value amount of tokens to burn.
     */
    function burnFrom(address recipient, uint256 value)
        external
        virtual
        returns (bool);

    /**
     * @notice Mints tokens and adds them to the balance of the `to` address.
     * @dev This method should be permissioned to only allow designated parties to mint tokens.
     */
    function mint(address to, uint256 value) external virtual returns (bool);

    function addMinter(address account) external virtual;

    function addBurner(address account) external virtual;

    function resetOwner(address account) external virtual;
}

File 11 of 18 : IERC20Standard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

File 12 of 18 : FinancialProductLibrary.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../../../common/implementation/FixedPoint.sol";

interface ExpiringContractInterface {
    function expirationTimestamp() external view returns (uint256);
}

/**
 * @title Financial product library contract
 * @notice Provides price and collateral requirement transformation interfaces that can be overridden by custom
 * Financial product library implementations.
 */
abstract contract FinancialProductLibrary {
    using FixedPoint for FixedPoint.Unsigned;

    /**
     * @notice Transforms a given oracle price using the financial product libraries transformation logic.
     * @param oraclePrice input price returned by the DVM to be transformed.
     * @return transformedOraclePrice input oraclePrice with the transformation function applied.
     */
    function transformPrice(FixedPoint.Unsigned memory oraclePrice, uint256)
        public
        view
        virtual
        returns (FixedPoint.Unsigned memory)
    {
        return oraclePrice;
    }

    /**
     * @notice Transforms a given collateral requirement using the financial product libraries transformation logic.
     * @param collateralRequirement input collateral requirement to be transformed.
     * @return transformedCollateralRequirement input collateral requirement with the transformation function applied.
     */
    function transformCollateralRequirement(
        FixedPoint.Unsigned memory,
        FixedPoint.Unsigned memory collateralRequirement
    ) public view virtual returns (FixedPoint.Unsigned memory) {
        return collateralRequirement;
    }

    /**
     * @notice Transforms a given price identifier using the financial product libraries transformation logic.
     * @param priceIdentifier input price identifier defined for the financial contract.
     * @return transformedPriceIdentifier input price identifier with the transformation function applied.
     */
    function transformPriceIdentifier(bytes32 priceIdentifier, uint256)
        public
        view
        virtual
        returns (bytes32)
    {
        return priceIdentifier;
    }
}

File 13 of 18 : Liquidatable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";

import "./PricelessPositionManager.sol";

import "../../common/implementation/FixedPoint.sol";

/**
 * @title Liquidatable
 * @notice Adds logic to a position-managing contract that enables callers to liquidate an undercollateralized position.
 * @dev The liquidation has a liveness period before expiring successfully, during which someone can "dispute" the
 * liquidation, which sends a price request to the relevant Oracle to settle the final collateralization ratio based on
 * a DVM price. The contract enforces dispute rewards in order to incentivize disputers to correctly dispute false
 * liquidations and compensate position sponsors who had their position incorrectly liquidated. Importantly, a
 * prospective disputer must deposit a dispute bond that they can lose in the case of an unsuccessful dispute.
 * NOTE: this contract does _not_ work with ERC777 collateral currencies or any others that call into the receiver on
 * transfer(). Using an ERC777 token would allow a user to maliciously grief other participants (while also losing
 * money themselves).
 */
contract Liquidatable is PricelessPositionManager {
    using FixedPoint for FixedPoint.Unsigned;
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using SafeERC20 for ExpandedIERC20;
    using Address for address;

    /****************************************
     *     LIQUIDATION DATA STRUCTURES      *
     ****************************************/

    // Because of the check in withdrawable(), the order of these enum values should not change.
    enum Status {
        Uninitialized,
        NotDisputed,
        Disputed,
        DisputeSucceeded,
        DisputeFailed
    }

    struct LiquidationData {
        address sponsor; // Address of the liquidated position's sponsor
        address liquidator; // Address who created this liquidation
        Status state; // Liquidated (and expired or not), Pending a Dispute, or Dispute has resolved
        uint256 liquidationTime; // Time when liquidation is initiated, needed to get price from Oracle
        // Following variables determined by the position that is being liquidated:
        FixedPoint.Unsigned tokensOutstanding; // Synthetic tokens required to be burned by liquidator to initiate dispute
        FixedPoint.Unsigned lockedCollateral; // Collateral locked by contract and released upon expiry or post-dispute
        // Amount of collateral locked in the liquidation if all pending slow withdrawals went through.
        // This value is used during disputes instead of lockedCollateral, so insolvent withdrawals can be punished.
        FixedPoint.Unsigned lockedCollateralAfterWithdrawals;
        // Following variables set upon initiation of a dispute:
        address disputer; // Person who is disputing a liquidation
        // Following variable set upon a resolution of a dispute:
        FixedPoint.Unsigned settlementPrice; // Final price as determined by an Oracle following a dispute
    }

    // Define the contract's constructor parameters as a struct to enable more variables to be specified.
    // This is required to enable more params, over and above Solidity's limits.
    struct ConstructorParams {
        // Params for PricelessPositionManager only.
        uint256 expirationTimestamp;
        uint256 withdrawalLiveness;
        address collateralAddress;
        address tokenAddress;
        address finderAddress;
        address financialProductLibraryAddress;
        bytes32 priceFeedIdentifier;
        bytes ancillaryData;
        FixedPoint.Unsigned minSponsorTokens;
        FixedPoint.Unsigned ooReward;
        // Params specifically for Liquidatable.
        uint256 liquidationLiveness;
        FixedPoint.Unsigned collateralRequirement;
        FixedPoint.Unsigned disputeBondPercentage;
        FixedPoint.Unsigned sponsorDisputeRewardPercentage;
        FixedPoint.Unsigned disputerDisputeRewardPercentage;
        address owner;
    }

    // This struct is used in the `withdrawLiquidation` method that disperses liquidation and dispute rewards.
    struct RewardsData {
        FixedPoint.Unsigned payToSponsor;
        FixedPoint.Unsigned payToLiquidator;
        FixedPoint.Unsigned payToDisputer;
    }

    // Liquidations are unique by ID per sponsor
    mapping(address => LiquidationData[]) public liquidations;

    // Total collateral in liquidation.
    FixedPoint.Unsigned public liquidationCollateral;

    // Immutable contract parameters:

    // Amount of time for pending liquidation before expiry.
    // !!Note: The lower the liquidation liveness value, the more risk incurred by sponsors.
    //       Extremely low liveness values increase the chance that opportunistic invalid liquidations
    //       expire without dispute, thereby decreasing the usability for sponsors and increasing the risk
    //       for the contract as a whole. An insolvent contract is extremely risky for any sponsor or synthetic
    //       token holder for the contract.
    uint256 public liquidationLiveness;
    // Required collateral:TRV ratio for a position to be considered sufficiently collateralized.
    FixedPoint.Unsigned public collateralRequirement;
    // Percent of a Liquidation/Position's lockedCollateral to be deposited by a potential disputer
    // Represented as a multiplier, for example 1.5e18 = "150%" and 0.05e18 = "5%"
    FixedPoint.Unsigned public disputeBondPercentage;
    // Percent of liquidated collateral paid to sponsor in the Disputed state (i.e. following a successful dispute)
    // Represented as a multiplier, see above.
    FixedPoint.Unsigned public sponsorDisputeRewardPercentage;
    // Percent of liquidated collateral paid to disputer in the Disputed state (i.e. following a successful dispute)
    // Represented as a multiplier, see above.
    FixedPoint.Unsigned public disputerDisputeRewardPercentage;

    /****************************************
     *                EVENTS                *
     ****************************************/

    event LiquidationCreated(
        address indexed sponsor,
        address indexed liquidator,
        uint256 indexed liquidationId,
        uint256 tokensOutstanding,
        uint256 lockedCollateral,
        uint256 lockedCollateralAfterWithdrawals,
        uint256 liquidationTime
    );
    event LiquidationDisputed(
        address indexed sponsor,
        address indexed liquidator,
        address indexed disputer,
        uint256 liquidationId,
        uint256 disputeBondAmount
    );
    event DisputeSettled(
        address indexed caller,
        address indexed sponsor,
        address indexed liquidator,
        address disputer,
        uint256 liquidationId,
        bool disputeSucceeded
    );
    event LiquidationWithdrawn(
        address indexed caller,
        uint256 paidToLiquidator,
        uint256 paidToDisputer,
        uint256 paidToSponsor,
        Status indexed liquidationStatus,
        uint256 settlementPrice
    );

    /****************************************
     *              MODIFIERS               *
     ****************************************/

    modifier disputable(uint256 liquidationId, address sponsor) {
        _disputable(liquidationId, sponsor);
        _;
    }

    modifier withdrawable(uint256 liquidationId, address sponsor) {
        _withdrawable(liquidationId, sponsor);
        _;
    }

    /**
     * @notice Constructs the liquidatable contract.
     * @param params struct to define input parameters for construction of Liquidatable. Some params
     * are fed directly into the PricelessPositionManager's constructor within the inheritance tree.
     */
    constructor(ConstructorParams memory params)
        PricelessPositionManager(
            params.expirationTimestamp,
            params.withdrawalLiveness,
            params.collateralAddress,
            params.tokenAddress,
            params.finderAddress,
            params.priceFeedIdentifier,
            params.minSponsorTokens,
            params.ooReward,
            params.financialProductLibraryAddress,
            params.ancillaryData,
            params.owner
        )
        nonReentrant()
    {
        require(params.collateralRequirement.isGreaterThan(1));
        require(
            params
                .sponsorDisputeRewardPercentage
                .add(params.disputerDisputeRewardPercentage)
                .isLessThan(1)
        );

        // Set liquidatable specific variables.
        liquidationLiveness = params.liquidationLiveness;
        collateralRequirement = params.collateralRequirement;
        disputeBondPercentage = params.disputeBondPercentage;
        sponsorDisputeRewardPercentage = params.sponsorDisputeRewardPercentage;
        disputerDisputeRewardPercentage = params
            .disputerDisputeRewardPercentage;
    }

    /****************************************
     *        LIQUIDATION FUNCTIONS         *
     ****************************************/

    /**
     * @notice Liquidates the sponsor's position if the caller has enough
     * synthetic tokens to retire the position's outstanding tokens. Liquidations above
     * a minimum size also reset an ongoing "slow withdrawal"'s liveness.
     * @dev This method generates an ID that will uniquely identify liquidation for the sponsor. This contract must be
     * approved to spend at least `tokensLiquidated` of `tokenCurrency` and at least `finalFeeBond` of `collateralCurrency`.
     * @dev This contract must have the Burner role for the `tokenCurrency`.
     * @param sponsor address of the sponsor to liquidate.
     * @param minCollateralPerToken abort the liquidation if the position's collateral per token is below this value.
     * @param maxCollateralPerToken abort the liquidation if the position's collateral per token exceeds this value.
     * @param maxTokensToLiquidate max number of tokens to liquidate.
     * @param deadline abort the liquidation if the transaction is mined after this timestamp.
     * @return liquidationId ID of the newly created liquidation.
     * @return tokensLiquidated amount of synthetic tokens removed and liquidated from the `sponsor`'s position.
     */
    function createLiquidation(
        address sponsor,
        FixedPoint.Unsigned calldata minCollateralPerToken,
        FixedPoint.Unsigned calldata maxCollateralPerToken,
        FixedPoint.Unsigned calldata maxTokensToLiquidate,
        uint256 deadline
    )
        external
        onlyPreExpiration
        nonReentrant
        returns (
            uint256 liquidationId,
            FixedPoint.Unsigned memory tokensLiquidated
        )
    {
        // Check that this transaction was mined pre-deadline.
        require(block.timestamp <= deadline, "Mined after deadline");

        // Retrieve Position data for sponsor
        PositionData storage positionToLiquidate = _getPositionData(sponsor);

        tokensLiquidated = FixedPoint.min(
            maxTokensToLiquidate,
            positionToLiquidate.tokensOutstanding
        );
        require(tokensLiquidated.isGreaterThan(0));

        // Starting values for the Position being liquidated. If withdrawal request amount is > position's collateral,
        // then set this to 0, otherwise set it to (startCollateral - withdrawal request amount).
        FixedPoint.Unsigned memory startCollateral = positionToLiquidate
            .collateral;
        FixedPoint.Unsigned memory startCollateralNetOfWithdrawal = FixedPoint
            .fromUnscaledUint(0);
        if (
            positionToLiquidate.withdrawalRequestAmount.isLessThanOrEqual(
                startCollateral
            )
        ) {
            startCollateralNetOfWithdrawal = startCollateral.sub(
                positionToLiquidate.withdrawalRequestAmount
            );
        }

        // Scoping to get rid of a stack too deep error.
        {
            FixedPoint.Unsigned memory startTokens = positionToLiquidate
                .tokensOutstanding;

            // The Position's collateralization ratio must be between [minCollateralPerToken, maxCollateralPerToken].
            // maxCollateralPerToken >= startCollateralNetOfWithdrawal / startTokens.
            require(
                maxCollateralPerToken.mul(startTokens).isGreaterThanOrEqual(
                    startCollateralNetOfWithdrawal
                ),
                "CR is more than max liq. price"
            );
            // minCollateralPerToken <= startCollateralNetOfWithdrawal / startTokens.
            require(
                minCollateralPerToken.mul(startTokens).isLessThanOrEqual(
                    startCollateralNetOfWithdrawal
                ),
                "CR is less than min liq. price"
            );
        }

        // These will be populated within the scope below.
        FixedPoint.Unsigned memory lockedCollateral;
        FixedPoint.Unsigned memory lockedCollateralAfterWithdrawals;

        // Scoping to get rid of a stack too deep error.
        {
            FixedPoint.Unsigned memory ratio = tokensLiquidated.div(
                positionToLiquidate.tokensOutstanding
            );

            // The actual amount of collateral that gets moved to the liquidation.
            lockedCollateral = startCollateral.mul(ratio);

            // For purposes of disputes, it's actually this lockedCollateralAfterWithdrawals value that's used.
            lockedCollateralAfterWithdrawals = startCollateralNetOfWithdrawal
                .mul(ratio);

            // Part of the withdrawal request is also removed. Ideally:
            // lockedCollateralAfterWithdrawals + withdrawalAmountToRemove = lockedCollateral.
            FixedPoint.Unsigned
                memory withdrawalAmountToRemove = positionToLiquidate
                    .withdrawalRequestAmount
                    .mul(ratio);

            _reduceSponsorPosition(
                sponsor,
                tokensLiquidated,
                lockedCollateral,
                withdrawalAmountToRemove
            );
        }

        // Add to the global liquidation collateral count.
        liquidationCollateral = liquidationCollateral.add(lockedCollateral).add(
                ooReward
            );

        // Construct liquidation object.
        // Note: All dispute-related values are zeroed out until a dispute occurs. liquidationId is the index of the new
        // LiquidationData that is pushed into the array, which is equal to the current length of the array pre-push.
        liquidationId = liquidations[sponsor].length;
        liquidations[sponsor].push(
            LiquidationData({
                sponsor: sponsor,
                liquidator: msg.sender,
                state: Status.NotDisputed,
                liquidationTime: block.timestamp,
                tokensOutstanding: tokensLiquidated,
                lockedCollateral: lockedCollateral,
                lockedCollateralAfterWithdrawals: lockedCollateralAfterWithdrawals,
                disputer: address(0),
                settlementPrice: FixedPoint.fromUnscaledUint(0)
            })
        );

        // If this liquidation is a subsequent liquidation on the position, and the liquidation size is larger than
        // some "griefing threshold", then re-set the liveness. This enables a liquidation against a withdraw request to be
        // "dragged out" if the position is very large and liquidators need time to gather funds. The griefing threshold
        // is enforced so that liquidations for trivially small # of tokens cannot drag out an honest sponsor's slow withdrawal.

        // We arbitrarily set the "griefing threshold" to `minSponsorTokens` because it is the only parameter
        // denominated in token currency units and we can avoid adding another parameter.
        FixedPoint.Unsigned memory griefingThreshold = minSponsorTokens;
        if (
            positionToLiquidate.withdrawalRequestPassTimestamp > 0 && // The position is undergoing a slow withdrawal.
            positionToLiquidate.withdrawalRequestPassTimestamp >
            block.timestamp && // The slow withdrawal has not yet expired.
            tokensLiquidated.isGreaterThanOrEqual(griefingThreshold) // The liquidated token count is above a "griefing threshold".
        ) {
            positionToLiquidate.withdrawalRequestPassTimestamp = (
                block.timestamp
            ).add(withdrawalLiveness);
        }

        emit LiquidationCreated(
            sponsor,
            msg.sender,
            liquidationId,
            tokensLiquidated.rawValue,
            lockedCollateral.rawValue,
            lockedCollateralAfterWithdrawals.rawValue,
            block.timestamp
        );

        // Destroy tokens
        tokenCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            tokensLiquidated.rawValue
        );
        tokenCurrency.burn(tokensLiquidated.rawValue);

        // Pull ooReward from liquidator.
        collateralCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            ooReward.rawValue
        );
    }

    /**
     * @notice Disputes a liquidation, if the caller has enough collateral to post a dispute bond
     * and pay a fixed ooReward charged on each price request.
     * @dev Can only dispute a liquidation before the liquidation expires and if there are no other pending disputes.
     * This contract must be approved to spend at least the dispute bond amount of `collateralCurrency`. This dispute
     * bond amount is calculated from `disputeBondPercentage` times the collateral in the liquidation.
     * @param liquidationId of the disputed liquidation.
     * @param sponsor the address of the sponsor whose liquidation is being disputed.
     * @return totalPaid amount of collateral charged to disputer (i.e. ooReward bond + dispute bond).
     */
    function dispute(uint256 liquidationId, address sponsor)
        external
        disputable(liquidationId, sponsor)
        nonReentrant
        returns (FixedPoint.Unsigned memory totalPaid)
    {
        LiquidationData storage disputedLiquidation = _getLiquidationData(
            sponsor,
            liquidationId
        );

        // Multiply by the unit collateral so the dispute bond is a percentage of the locked collateral after fees.
        FixedPoint.Unsigned memory disputeBondAmount = disputedLiquidation
            .lockedCollateral
            .mul(disputeBondPercentage);
        liquidationCollateral = liquidationCollateral.add(disputeBondAmount);

        // Request a price from Optimistic Oracle. Liquidation is pending dispute until OO returns a price.
        disputedLiquidation.state = Status.Disputed;
        disputedLiquidation.disputer = msg.sender;

        // Enqueue a request with the Optimistic Oracle.
        _requestOraclePrice_senderPays(disputedLiquidation.liquidationTime);

        emit LiquidationDisputed(
            sponsor,
            disputedLiquidation.liquidator,
            msg.sender,
            liquidationId,
            disputeBondAmount.rawValue
        );
        totalPaid = disputeBondAmount.add(ooReward);

        // Transfer the dispute bond amount from the caller to this contract.
        collateralCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            disputeBondAmount.rawValue
        );
    }

    /**
     * @notice After a dispute has settled or after a non-disputed liquidation has expired,
     * anyone can call this method to disperse payments to the sponsor, liquidator, and disdputer.
     * @dev If the dispute SUCCEEDED: the sponsor, liquidator, and disputer are eligible for payment.
     * If the dispute FAILED: only the liquidator can receive payment.
     * This method will revert if rewards have already been dispersed.
     * @param liquidationId uniquely identifies the sponsor's liquidation.
     * @param sponsor address of the sponsor associated with the liquidation.
     * @return data about rewards paid out.
     */
    function withdrawLiquidation(uint256 liquidationId, address sponsor)
        public
        withdrawable(liquidationId, sponsor)
        nonReentrant
        returns (RewardsData memory)
    {
        LiquidationData storage liquidation = _getLiquidationData(
            sponsor,
            liquidationId
        );

        // Settles the liquidation if necessary. This call will revert if the price has not resolved yet.
        _settle(liquidationId, sponsor);

        // Calculate rewards as a function of the TRV.
        FixedPoint.Unsigned memory tokenRedemptionValue = liquidation
            .tokensOutstanding
            .mul(liquidation.settlementPrice);
        FixedPoint.Unsigned
            memory disputerDisputeReward = disputerDisputeRewardPercentage.mul(
                tokenRedemptionValue
            );
        FixedPoint.Unsigned
            memory sponsorDisputeReward = sponsorDisputeRewardPercentage.mul(
                tokenRedemptionValue
            );
        FixedPoint.Unsigned memory disputeBondAmount = liquidation
            .lockedCollateral
            .mul(disputeBondPercentage);

        // There are three main outcome states: either the dispute succeeded, failed or was not updated.
        // Based on the state, different parties of a liquidation receive different amounts.
        // After assigning rewards based on the liquidation status, decrease the total collateral held in this contract
        // by the amount to pay each party. The actual amounts withdrawn might differ if _removeCollateral causes
        // precision loss.
        RewardsData memory rewards;
        if (liquidation.state == Status.DisputeSucceeded) {
            // If the dispute is successful then all three users should receive rewards:

            // Pay DISPUTER: disputer reward + dispute bond + returned ooReward
            rewards.payToDisputer = disputerDisputeReward
                .add(disputeBondAmount)
                .add(ooReward);

            // Pay SPONSOR: remaining collateral (collateral - TRV) + sponsor reward
            rewards.payToSponsor = liquidation
                .lockedCollateral
                .sub(tokenRedemptionValue)
                .add(sponsorDisputeReward);

            // Pay LIQUIDATOR: TRV - dispute reward - sponsor reward
            // If TRV > Collateral, then subtract rewards from collateral
            // NOTE: `payToLiquidator` should never be below zero since we enforce that
            // (sponsorDisputePct+disputerDisputePct) <= 1 in the constructor when these params are set.
            rewards.payToLiquidator = tokenRedemptionValue
                .sub(sponsorDisputeReward)
                .sub(disputerDisputeReward);

            // Transfer rewards and debit collateral
            liquidationCollateral = liquidationCollateral.sub(
                rewards.payToLiquidator
            );
            liquidationCollateral = liquidationCollateral.sub(
                rewards.payToSponsor
            );
            liquidationCollateral = liquidationCollateral.sub(
                rewards.payToDisputer
            );

            collateralCurrency.safeTransfer(
                liquidation.disputer,
                rewards.payToDisputer.rawValue
            );
            collateralCurrency.safeTransfer(
                liquidation.liquidator,
                rewards.payToLiquidator.rawValue
            );
            collateralCurrency.safeTransfer(
                liquidation.sponsor,
                rewards.payToSponsor.rawValue
            );
        } else if (liquidation.state == Status.DisputeFailed) {
            // In the case of a failed dispute only the liquidator can withdraw.

            // Pay LIQUIDATOR: collateral + dispute bond + returned ooReward
            rewards.payToLiquidator = liquidation
                .lockedCollateral
                .add(disputeBondAmount)
                .add(ooReward);

            // Transfer rewards and debit collateral
            liquidationCollateral = liquidationCollateral.sub(
                rewards.payToLiquidator
            );

            collateralCurrency.safeTransfer(
                liquidation.liquidator,
                rewards.payToLiquidator.rawValue
            );
        } else if (liquidation.state == Status.NotDisputed) {
            // If the state is pre-dispute but time has passed liveness then there was no dispute. We represent this
            // state as a dispute failed and the liquidator can withdraw.

            // Pay LIQUIDATOR: collateral + returned ooReward
            rewards.payToLiquidator = liquidation.lockedCollateral.add(
                ooReward
            );

            // Transfer rewards and debit collateral
            liquidationCollateral = liquidationCollateral.sub(
                rewards.payToLiquidator
            );

            collateralCurrency.safeTransfer(
                liquidation.liquidator,
                rewards.payToLiquidator.rawValue
            );
        }

        emit LiquidationWithdrawn(
            msg.sender,
            rewards.payToLiquidator.rawValue,
            rewards.payToDisputer.rawValue,
            rewards.payToSponsor.rawValue,
            liquidation.state,
            liquidation.settlementPrice.rawValue
        );

        // Free up space after collateral is withdrawn by removing the liquidation object from the array.
        delete liquidations[sponsor][liquidationId];

        return rewards;
    }

    /**
     * @notice Gets all liquidation information for a given sponsor address.
     * @param sponsor address of the position sponsor.
     * @return liquidationData array of all liquidation information for the given sponsor address.
     */
    function getLiquidations(address sponsor)
        external
        view
        nonReentrantView
        returns (LiquidationData[] memory liquidationData)
    {
        return liquidations[sponsor];
    }

    /**
     * @notice Accessor method to calculate a transformed collateral requirement using the finanical product library
      specified during contract deployment. If no library was provided then no modification to the collateral requirement is done.
     * @param price input price used as an input to transform the collateral requirement.
     * @return transformedCollateralRequirement collateral requirement with transformation applied to it.
     * @dev This method should never revert.
     */
    function transformCollateralRequirement(FixedPoint.Unsigned memory price)
        public
        view
        nonReentrantView
        returns (FixedPoint.Unsigned memory)
    {
        return _transformCollateralRequirement(price);
    }

    /****************************************
     *          INTERNAL FUNCTIONS          *
     ****************************************/

    // This settles a liquidation if it is in the Disputed state. If not, it will immediately return.
    // If the liquidation is in the Disputed state, but a price is not available, this will revert.
    function _settle(uint256 liquidationId, address sponsor) internal {
        LiquidationData storage liquidation = _getLiquidationData(
            sponsor,
            liquidationId
        );

        // Settlement only happens when state == Disputed and will only happen once per liquidation.
        // If this liquidation is not ready to be settled, this method should return immediately.
        if (liquidation.state != Status.Disputed) {
            return;
        }

        // Get the returned price from the oracle. If this has not yet resolved will revert.
        liquidation.settlementPrice = _getOraclePrice(
            liquidation.liquidationTime
        );

        // Find the value of the tokens in the underlying collateral.
        FixedPoint.Unsigned memory tokenRedemptionValue = liquidation
            .tokensOutstanding
            .mul(liquidation.settlementPrice);

        // The required collateral is the value of the tokens in underlying * required collateral ratio. The Transform
        // Collateral requirement method applies a from the financial Product library to change the scaled the collateral
        // requirement based on the settlement price. If no library was specified when deploying the emp then this makes no change.
        FixedPoint.Unsigned memory requiredCollateral = tokenRedemptionValue
            .mul(_transformCollateralRequirement(liquidation.settlementPrice));

        // If the position has more than the required collateral it is solvent and the dispute is valid(liquidation is invalid)
        // Note that this check uses the lockedCollateralAfterWithdrawals not the lockedCollateral as this considers withdrawals.
        bool disputeSucceeded = liquidation
            .lockedCollateralAfterWithdrawals
            .isGreaterThanOrEqual(requiredCollateral);

        liquidation.state = disputeSucceeded
            ? Status.DisputeSucceeded
            : Status.DisputeFailed;

        emit DisputeSettled(
            msg.sender,
            sponsor,
            liquidation.liquidator,
            liquidation.disputer,
            liquidationId,
            disputeSucceeded
        );
    }

    function _getLiquidationData(address sponsor, uint256 liquidationId)
        internal
        view
        returns (LiquidationData storage liquidation)
    {
        LiquidationData[] storage liquidationArray = liquidations[sponsor];

        // Revert if the caller is attempting to access an invalid liquidation
        // (one that has never been created or one has never been initialized).
        require(
            liquidationId < liquidationArray.length &&
                liquidationArray[liquidationId].state != Status.Uninitialized,
            "Invalid liquidation ID"
        );
        return liquidationArray[liquidationId];
    }

    function _getLiquidationExpiry(LiquidationData storage liquidation)
        internal
        view
        returns (uint256)
    {
        return liquidation.liquidationTime.add(liquidationLiveness);
    }

    // These internal functions are supposed to act identically to modifiers, but re-used modifiers
    // unnecessarily increase contract bytecode size.
    // source: https://blog.polymath.network/solidity-tips-and-tricks-to-save-gas-and-reduce-bytecode-size-c44580b218e6
    function _disputable(uint256 liquidationId, address sponsor) internal view {
        LiquidationData storage liquidation = _getLiquidationData(
            sponsor,
            liquidationId
        );
        require(
            (block.timestamp < _getLiquidationExpiry(liquidation)) &&
                (liquidation.state == Status.NotDisputed),
            "Liquidation not disputable"
        );
    }

    function _withdrawable(uint256 liquidationId, address sponsor)
        internal
        view
    {
        LiquidationData storage liquidation = _getLiquidationData(
            sponsor,
            liquidationId
        );
        Status state = liquidation.state;

        // Must be disputed or the liquidation has passed expiry.
        require(
            (state > Status.NotDisputed) ||
                ((_getLiquidationExpiry(liquidation) <= block.timestamp) &&
                    (state == Status.NotDisputed)),
            "Liquidation not withdrawable"
        );
    }

    function _transformCollateralRequirement(FixedPoint.Unsigned memory price)
        internal
        view
        returns (FixedPoint.Unsigned memory)
    {
        if (!address(financialProductLibrary).isContract())
            return collateralRequirement;
        try
            financialProductLibrary.transformCollateralRequirement(
                price,
                collateralRequirement
            )
        returns (FixedPoint.Unsigned memory transformedCollateralRequirement) {
            return transformedCollateralRequirement;
        } catch {
            return collateralRequirement;
        }
    }
}

File 14 of 18 : PricelessPositionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";

import "../../common/implementation/FixedPoint.sol";
import "../../common/interfaces/ExpandedIERC20.sol";
import "../../common/interfaces/IERC20Standard.sol";

import "../../oracle/interfaces/OptimisticOracleInterface.sol";
import "../../oracle/interfaces/IdentifierWhitelistInterface.sol";

import "../../oracle/implementation/Constants.sol";
import "../../common/implementation/Lockable.sol";

import "../common/financial-product-libraries/expiring-multiparty-libraries/FinancialProductLibrary.sol";

/**
 * @title Financial contract with priceless position management.
 * @notice Handles positions for multiple sponsors in an optimistic (i.e., priceless) way without relying
 * on a price feed. On construction, deploys a new ERC20, managed by this contract, that is the synthetic token.
 */

contract PricelessPositionManager is Lockable {
    using SafeMath for uint256;
    using FixedPoint for FixedPoint.Unsigned;
    using SafeERC20 for IERC20;
    using SafeERC20 for ExpandedIERC20;
    using Address for address;

    /****************************************
     *  PRICELESS POSITION DATA STRUCTURES  *
     ****************************************/

    // Stores the state of the PricelessPositionManager. Set on expiration, emergency shutdown, or settlement.
    enum ContractState {
        Open,
        ExpiredPriceRequested,
        ExpiredPriceReceived
    }
    ContractState public contractState;

    // Represents a single sponsor's position. All collateral is held by this contract.
    // This struct acts as bookkeeping for how much of that collateral is allocated to each sponsor.
    struct PositionData {
        FixedPoint.Unsigned tokensOutstanding;
        // Tracks pending withdrawal requests. A withdrawal request is pending if `withdrawalRequestPassTimestamp != 0`.
        uint256 withdrawalRequestPassTimestamp;
        FixedPoint.Unsigned withdrawalRequestAmount;
        // Collateral value.
        FixedPoint.Unsigned collateral;
        // Tracks pending transfer position requests. A transfer position request is pending if `transferPositionRequestPassTimestamp != 0`.
        uint256 transferPositionRequestPassTimestamp;
    }

    // Maps sponsor addresses to their positions. Each sponsor can have only one position.
    mapping(address => PositionData) public positions;

    // Keep track of the total collateral and tokens across all positions to enable calculating the
    // global collateralization ratio without iterating over all positions.
    FixedPoint.Unsigned public totalTokensOutstanding;

    // Total position collateral.
    FixedPoint.Unsigned public totalPositionCollateral;

    // Synthetic token created by this contract.
    ExpandedIERC20 public tokenCurrency;

    // The collateral currency used to back the positions in this contract.
    IERC20 public collateralCurrency;

    // Finder contract used to look up addresses for UMA system contracts.
    FinderInterface public finder;

    // Unique identifier for DVM price feed ticker.
    bytes32 public priceIdentifier;
    // Ancillary data to pass to the Optimistic Oracle system when requesting and fetching prices
    bytes public ancillaryData;

    // Time that this contract expires. Should not change post-construction unless an emergency shutdown occurs.
    uint256 public expirationTimestamp;
    // Time that has to elapse for a withdrawal request to be considered passed, if no liquidations occur.
    // !!Note: The lower the withdrawal liveness value, the more risk incurred by the contract.
    //       Extremely low liveness values increase the chance that opportunistic invalid withdrawal requests
    //       expire without liquidation, thereby increasing the insolvency risk for the contract as a whole. An insolvent
    //       contract is extremely risky for any sponsor or synthetic token holder for the contract.
    uint256 public withdrawalLiveness;

    // Minimum number of tokens in a sponsor's position.
    FixedPoint.Unsigned public minSponsorTokens;

    // The expiry price pulled from the DVM.
    FixedPoint.Unsigned public expiryPrice;

    // How much to offer the Optimistic Oracle as a reward for price requests
    FixedPoint.Unsigned public ooReward;

    address public owner;
    // Instance of FinancialProductLibrary to provide custom price and collateral requirement transformations to extend
    // the functionality of the EMP to support a wider range of financial products.
    FinancialProductLibrary public financialProductLibrary;

    /****************************************
     *                EVENTS                *
     ****************************************/

    event RequestTransferPosition(address indexed oldSponsor);
    event RequestTransferPositionExecuted(
        address indexed oldSponsor,
        address indexed newSponsor
    );
    event RequestTransferPositionCanceled(address indexed oldSponsor);
    event Deposit(address indexed sponsor, uint256 indexed collateralAmount);
    event Withdrawal(address indexed sponsor, uint256 indexed collateralAmount);
    event RequestWithdrawal(
        address indexed sponsor,
        uint256 indexed collateralAmount
    );
    event RequestWithdrawalExecuted(
        address indexed sponsor,
        uint256 indexed collateralAmount
    );
    event RequestWithdrawalCanceled(
        address indexed sponsor,
        uint256 indexed collateralAmount
    );
    event PositionCreated(
        address indexed sponsor,
        uint256 indexed collateralAmount,
        uint256 indexed tokenAmount
    );
    event NewSponsor(address indexed sponsor);
    event EndedSponsorPosition(address indexed sponsor);
    event Repay(
        address indexed sponsor,
        uint256 indexed numTokensRepaid,
        uint256 indexed newTokenCount
    );
    event Redeem(
        address indexed sponsor,
        uint256 indexed collateralAmount,
        uint256 indexed tokenAmount
    );
    event ContractExpired(address indexed caller);
    event SettleExpiredPosition(
        address indexed caller,
        uint256 indexed collateralReturned,
        uint256 indexed tokensBurned
    );
    event EmergencyShutdown(
        address indexed caller,
        uint256 originalExpirationTimestamp,
        uint256 shutdownTimestamp
    );
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /****************************************
     *               MODIFIERS              *
     ****************************************/

    modifier onlyPreExpiration() {
        _onlyPreExpiration();
        _;
    }

    modifier onlyPostExpiration() {
        _onlyPostExpiration();
        _;
    }

    modifier onlyCollateralizedPosition(address sponsor) {
        _onlyCollateralizedPosition(sponsor);
        _;
    }

    // Check that the current state of the pricelessPositionManager is Open.
    // This prevents multiple calls to `expire` and `EmergencyShutdown` post expiration.
    modifier onlyOpenState() {
        _onlyOpenState();
        _;
    }

    modifier noPendingWithdrawal(address sponsor) {
        _positionHasNoPendingWithdrawal(sponsor);
        _;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(msg.sender == owner, "caller is not the owner");
        _;
    }

    /**
     * @notice Construct the PricelessPositionManager
     * @dev Deployer of this contract should consider carefully which parties have ability to mint and burn
     * the synthetic tokens referenced by `_tokenAddress`. This contract's security assumes that no external accounts
     * can mint new tokens, which could be used to steal all of this contract's locked collateral.
     * We recommend to only use synthetic token contracts whose sole Owner role (the role capable of adding & removing roles)
     * is assigned to this contract, whose sole Minter role is assigned to this contract, and whose
     * total supply is 0 prior to construction of this contract.
     * @param _expirationTimestamp unix timestamp of when the contract will expire.
     * @param _withdrawalLiveness liveness delay, in seconds, for pending withdrawals.
     * @param _collateralAddress ERC20 token used as collateral for all positions.
     * @param _tokenAddress ERC20 token used as synthetic token.
     * @param _finderAddress UMA protocol Finder used to discover other protocol contracts.
     * @param _priceIdentifier registered in the DVM for the synthetic.
     * @param _minSponsorTokens minimum number of tokens that must exist at any time in a position.
     * @param _ooReward How much collateral to offer to the Optimistic Oracle when resolving prices
     * Must be set to 0x0 for production environments that use live time.
     * @param _financialProductLibraryAddress Contract providing contract state transformations.
     */
    constructor(
        uint256 _expirationTimestamp,
        uint256 _withdrawalLiveness,
        address _collateralAddress,
        address _tokenAddress,
        address _finderAddress,
        bytes32 _priceIdentifier,
        FixedPoint.Unsigned memory _minSponsorTokens,
        FixedPoint.Unsigned memory _ooReward,
        address _financialProductLibraryAddress,
        bytes memory _ancillaryData,
        address _owner
    ) nonReentrant() {
        finder = FinderInterface(_finderAddress);

        require(_expirationTimestamp > block.timestamp);
        require(
            _getIdentifierWhitelist().isIdentifierSupported(_priceIdentifier)
        );

        expirationTimestamp = _expirationTimestamp;
        withdrawalLiveness = _withdrawalLiveness;
        tokenCurrency = ExpandedIERC20(_tokenAddress);
        collateralCurrency = IERC20(_collateralAddress);
        minSponsorTokens = _minSponsorTokens;
        ooReward = _ooReward;
        priceIdentifier = _priceIdentifier;
        ancillaryData = _ancillaryData;
        owner = _owner;

        // Initialize the financialProductLibrary at the provided address.
        financialProductLibrary = FinancialProductLibrary(
            _financialProductLibraryAddress
        );
    }

    /****************************************
     *          POSITION FUNCTIONS          *
     ****************************************/

    /**
     * @notice Requests to transfer ownership of the caller's current position to a new sponsor address.
     * Once the request liveness is passed, the sponsor can execute the transfer and specify the new sponsor.
     * @dev The liveness length is the same as the withdrawal liveness.
     */
    function requestTransferPosition() public onlyPreExpiration nonReentrant {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(positionData.transferPositionRequestPassTimestamp == 0);

        // Make sure the proposed expiration of this request is not post-expiry.
        uint256 requestPassTime = (block.timestamp).add(withdrawalLiveness);
        require(requestPassTime < expirationTimestamp);

        // Update the position object for the user.
        positionData.transferPositionRequestPassTimestamp = requestPassTime;

        emit RequestTransferPosition(msg.sender);
    }

    /**
     * @notice After a passed transfer position request (i.e., by a call to `requestTransferPosition` and waiting
     * `withdrawalLiveness`), transfers ownership of the caller's current position to `newSponsorAddress`.
     * @dev Transferring positions can only occur if the recipient does not already have a position.
     * @param newSponsorAddress is the address to which the position will be transferred.
     */
    function transferPositionPassedRequest(address newSponsorAddress)
        public
        onlyPreExpiration
        noPendingWithdrawal(msg.sender)
        nonReentrant
    {
        require(
            positions[newSponsorAddress].collateral.isEqual(
                FixedPoint.fromUnscaledUint(0)
            )
        );
        PositionData storage positionData = _getPositionData(msg.sender);
        require(
            positionData.transferPositionRequestPassTimestamp != 0 &&
                positionData.transferPositionRequestPassTimestamp <=
                block.timestamp
        );

        // Reset transfer request.
        positionData.transferPositionRequestPassTimestamp = 0;

        positions[newSponsorAddress] = positionData;
        delete positions[msg.sender];

        emit RequestTransferPositionExecuted(msg.sender, newSponsorAddress);
        emit NewSponsor(newSponsorAddress);
        emit EndedSponsorPosition(msg.sender);
    }

    /**
     * @notice Cancels a pending transfer position request.
     */
    function cancelTransferPosition() external onlyPreExpiration nonReentrant {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(positionData.transferPositionRequestPassTimestamp != 0);

        emit RequestTransferPositionCanceled(msg.sender);

        // Reset withdrawal request.
        positionData.transferPositionRequestPassTimestamp = 0;
    }

    /**
     * @notice Transfers `collateralAmount` of `collateralCurrency` into the specified sponsor's position.
     * @dev Increases the collateralization level of a position after creation. This contract must be approved to spend
     * at least `collateralAmount` of `collateralCurrency`.
     * @param sponsor the sponsor to credit the deposit to.
     * @param collateralAmount total amount of collateral tokens to be sent to the sponsor's position.
     */
    function depositTo(
        address sponsor,
        FixedPoint.Unsigned memory collateralAmount
    ) public onlyPreExpiration noPendingWithdrawal(sponsor) nonReentrant {
        require(collateralAmount.isGreaterThan(0));
        PositionData storage positionData = _getPositionData(sponsor);

        // Increase the position and global collateral balance by collateral amount.
        _incrementCollateralBalances(positionData, collateralAmount);

        emit Deposit(sponsor, collateralAmount.rawValue);

        // Move collateral currency from sender to contract.
        collateralCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            collateralAmount.rawValue
        );
    }

    /**
     * @notice Transfers `collateralAmount` of `collateralCurrency` into the caller's position.
     * @dev Increases the collateralization level of a position after creation. This contract must be approved to spend
     * at least `collateralAmount` of `collateralCurrency`.
     * @param collateralAmount total amount of collateral tokens to be sent to the sponsor's position.
     */
    function deposit(FixedPoint.Unsigned memory collateralAmount) public {
        // This is just a thin wrapper over depositTo that specified the sender as the sponsor.
        depositTo(msg.sender, collateralAmount);
    }

    /**
     * @notice Transfers `collateralAmount` of `collateralCurrency` from the sponsor's position to the sponsor.
     * @dev Reverts if the withdrawal puts this position's collateralization ratio below the global collateralization
     * ratio. In that case, use `requestWithdrawal`. Might not withdraw the full requested amount to account for precision loss.
     * @param collateralAmount is the amount of collateral to withdraw.
     * @return amountWithdrawn The actual amount of collateral withdrawn.
     */
    function withdraw(FixedPoint.Unsigned memory collateralAmount)
        public
        onlyPreExpiration
        noPendingWithdrawal(msg.sender)
        nonReentrant
        returns (FixedPoint.Unsigned memory amountWithdrawn)
    {
        require(collateralAmount.isGreaterThan(0));
        PositionData storage positionData = _getPositionData(msg.sender);

        // Decrement the sponsor's collateral and global collateral amounts. Check the GCR between decrement to ensure
        // position remains above the GCR within the withdrawal. If this is not the case the caller must submit a request.
        amountWithdrawn = _decrementCollateralBalancesCheckGCR(
            positionData,
            collateralAmount
        );

        emit Withdrawal(msg.sender, amountWithdrawn.rawValue);

        // Move collateral currency from contract to sender.
        collateralCurrency.safeTransfer(msg.sender, amountWithdrawn.rawValue);
    }

    /**
     * @notice Starts a withdrawal request that, if passed, allows the sponsor to withdraw` from their position.
     * @dev The request will be pending for `withdrawalLiveness`, during which the position can be liquidated.
     * @param collateralAmount the amount of collateral requested to withdraw
     */
    function requestWithdrawal(FixedPoint.Unsigned memory collateralAmount)
        public
        onlyPreExpiration
        noPendingWithdrawal(msg.sender)
        nonReentrant
    {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(
            collateralAmount.isGreaterThan(0) &&
                collateralAmount.isLessThanOrEqual(positionData.collateral)
        );

        // Make sure the proposed expiration of this request is not post-expiry.
        uint256 requestPassTime = (block.timestamp).add(withdrawalLiveness);
        require(requestPassTime < expirationTimestamp);

        // Update the position object for the user.
        positionData.withdrawalRequestPassTimestamp = requestPassTime;
        positionData.withdrawalRequestAmount = collateralAmount;

        emit RequestWithdrawal(msg.sender, collateralAmount.rawValue);
    }

    /**
     * @notice After a passed withdrawal request (i.e., by a call to `requestWithdrawal` and waiting
     * `withdrawalLiveness`), withdraws `positionData.withdrawalRequestAmount` of collateral currency.
     * @dev Might not withdraw the full requested amount in order to account for precision loss or if the full requested
     * amount exceeds the collateral in the position (due to paying fees).
     * @return amountWithdrawn The actual amount of collateral withdrawn.
     */
    function withdrawPassedRequest()
        external
        onlyPreExpiration
        nonReentrant
        returns (FixedPoint.Unsigned memory amountWithdrawn)
    {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(
            positionData.withdrawalRequestPassTimestamp != 0 &&
                positionData.withdrawalRequestPassTimestamp <= block.timestamp
        );

        // If withdrawal request amount is > position collateral, then withdraw the full collateral amount.
        FixedPoint.Unsigned memory amountToWithdraw;
        if (
            positionData.withdrawalRequestAmount.isGreaterThan(
                positionData.collateral
            )
        ) {
            amountToWithdraw = positionData.collateral;
        } else {
            amountToWithdraw = positionData.withdrawalRequestAmount;
        }

        // Decrement the sponsor's collateral and global collateral amounts.
        amountWithdrawn = _decrementCollateralBalances(
            positionData,
            amountToWithdraw
        );

        // Reset withdrawal request by setting withdrawal amount and withdrawal timestamp to 0.
        _resetWithdrawalRequest(positionData);

        // Transfer approved withdrawal amount from the contract to the caller.
        collateralCurrency.safeTransfer(msg.sender, amountWithdrawn.rawValue);

        emit RequestWithdrawalExecuted(msg.sender, amountWithdrawn.rawValue);
    }

    /**
     * @notice Cancels a pending withdrawal request.
     */
    function cancelWithdrawal() external nonReentrant {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(positionData.withdrawalRequestPassTimestamp != 0);

        emit RequestWithdrawalCanceled(
            msg.sender,
            positionData.withdrawalRequestAmount.rawValue
        );

        // Reset withdrawal request by setting withdrawal amount and withdrawal timestamp to 0.
        _resetWithdrawalRequest(positionData);
    }

    /**
     * @notice Creates tokens by creating a new position or by augmenting an existing position. Pulls `collateralAmount` into the sponsor's position and mints `numTokens` of `tokenCurrency`.
     * @dev Reverts if minting these tokens would put the position's collateralization ratio below the
     * global collateralization ratio. This contract must be approved to spend at least `collateralAmount` of
     * `collateralCurrency`.
     * @dev This contract must have the Minter role for the `tokenCurrency`.
     * @param collateralAmount is the number of collateral tokens to collateralize the position with
     * @param numTokens is the number of tokens to mint from the position.
     */
    function create(
        FixedPoint.Unsigned memory collateralAmount,
        FixedPoint.Unsigned memory numTokens
    ) public onlyPreExpiration nonReentrant {
        PositionData storage positionData = positions[msg.sender];

        // Either the new create ratio or the resultant position CR must be above the current GCR.
        require(
            (_checkCollateralization(
                positionData.collateral.add(collateralAmount),
                positionData.tokensOutstanding.add(numTokens)
            ) || _checkCollateralization(collateralAmount, numTokens)),
            "Insufficient collateral"
        );

        require(
            positionData.withdrawalRequestPassTimestamp == 0,
            "Pending withdrawal"
        );

        if (positionData.tokensOutstanding.isEqual(0)) {
            require(
                numTokens.isGreaterThanOrEqual(minSponsorTokens),
                "Below minimum sponsor position"
            );
            emit NewSponsor(msg.sender);
        }

        // Increase the position and global collateral balance by collateral amount.
        _incrementCollateralBalances(positionData, collateralAmount);

        // Add the number of tokens created to the position's outstanding tokens.
        positionData.tokensOutstanding = positionData.tokensOutstanding.add(
            numTokens
        );
        totalTokensOutstanding = totalTokensOutstanding.add(numTokens);

        emit PositionCreated(
            msg.sender,
            collateralAmount.rawValue,
            numTokens.rawValue
        );

        // Transfer tokens into the contract from caller and mint corresponding synthetic tokens to the caller's address.
        collateralCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            collateralAmount.rawValue
        );
        require(tokenCurrency.mint(msg.sender, numTokens.rawValue));
    }

    /**
     * @notice Burns `numTokens` of `tokenCurrency` to decrease sponsors position size, without sending back `collateralCurrency`.
     * This is done by a sponsor to increase position CR. Resulting size is bounded by minSponsorTokens.
     * @dev Can only be called by token sponsor. This contract must be approved to spend `numTokens` of `tokenCurrency`.
     * @dev This contract must have the Burner role for the `tokenCurrency`.
     * @param numTokens is the number of tokens to be burnt from the sponsor's debt position.
     */
    function repay(FixedPoint.Unsigned memory numTokens)
        public
        onlyPreExpiration
        noPendingWithdrawal(msg.sender)
        nonReentrant
    {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(numTokens.isLessThanOrEqual(positionData.tokensOutstanding));

        // Decrease the sponsors position tokens size. Ensure it is above the min sponsor size.
        FixedPoint.Unsigned memory newTokenCount = positionData
            .tokensOutstanding
            .sub(numTokens);
        require(newTokenCount.isGreaterThanOrEqual(minSponsorTokens));
        positionData.tokensOutstanding = newTokenCount;

        // Update the totalTokensOutstanding after redemption.
        totalTokensOutstanding = totalTokensOutstanding.sub(numTokens);

        emit Repay(msg.sender, numTokens.rawValue, newTokenCount.rawValue);

        // Transfer the tokens back from the sponsor and burn them.
        tokenCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            numTokens.rawValue
        );
        tokenCurrency.burn(numTokens.rawValue);
    }

    /**
     * @notice Burns `numTokens` of `tokenCurrency` and sends back the proportional amount of `collateralCurrency`.
     * @dev Can only be called by a token sponsor. Might not redeem the full proportional amount of collateral
     * in order to account for precision loss. This contract must be approved to spend at least `numTokens` of
     * `tokenCurrency`.
     * @dev This contract must have the Burner role for the `tokenCurrency`.
     * @param numTokens is the number of tokens to be burnt for a commensurate amount of collateral.
     * @return amountWithdrawn The actual amount of collateral withdrawn.
     */
    function redeem(FixedPoint.Unsigned memory numTokens)
        public
        noPendingWithdrawal(msg.sender)
        nonReentrant
        returns (FixedPoint.Unsigned memory amountWithdrawn)
    {
        PositionData storage positionData = _getPositionData(msg.sender);
        require(!numTokens.isGreaterThan(positionData.tokensOutstanding));

        FixedPoint.Unsigned memory fractionRedeemed = numTokens.div(
            positionData.tokensOutstanding
        );
        FixedPoint.Unsigned memory collateralRedeemed = fractionRedeemed.mul(
            positionData.collateral
        );

        // If redemption returns all tokens the sponsor has then we can delete their position. Else, downsize.
        if (positionData.tokensOutstanding.isEqual(numTokens)) {
            amountWithdrawn = _deleteSponsorPosition(msg.sender);
        } else {
            // Decrement the sponsor's collateral and global collateral amounts.
            amountWithdrawn = _decrementCollateralBalances(
                positionData,
                collateralRedeemed
            );

            // Decrease the sponsors position tokens size. Ensure it is above the min sponsor size.
            FixedPoint.Unsigned memory newTokenCount = positionData
                .tokensOutstanding
                .sub(numTokens);
            require(
                newTokenCount.isGreaterThanOrEqual(minSponsorTokens),
                "Below minimum sponsor position"
            );
            positionData.tokensOutstanding = newTokenCount;

            // Update the totalTokensOutstanding after redemption.
            totalTokensOutstanding = totalTokensOutstanding.sub(numTokens);
        }

        emit Redeem(msg.sender, amountWithdrawn.rawValue, numTokens.rawValue);

        // Transfer collateral from contract to caller and burn callers synthetic tokens.
        collateralCurrency.safeTransfer(msg.sender, amountWithdrawn.rawValue);
        tokenCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            numTokens.rawValue
        );
        tokenCurrency.burn(numTokens.rawValue);
    }

    /**
     * @notice After a contract has passed expiry all token holders can redeem their tokens for underlying at the
     * prevailing price defined by the DVM from the `expire` function.
     * @dev This burns all tokens from the caller of `tokenCurrency` and sends back the proportional amount of
     * `collateralCurrency`. Might not redeem the full proportional amount of collateral in order to account for
     * precision loss. This contract must be approved to spend `tokenCurrency` at least up to the caller's full balance.
     * @dev This contract must have the Burner role for the `tokenCurrency`.
     * @return amountWithdrawn The actual amount of collateral withdrawn.
     */
    function settleExpired()
        external
        onlyPostExpiration
        nonReentrant
        returns (FixedPoint.Unsigned memory amountWithdrawn)
    {
        // If the contract state is open and onlyPostExpiration passed then `expire()` has not yet been called.
        require(contractState != ContractState.Open, "Unexpired position");

        // Get the current settlement price and store it. If it is not resolved will revert.
        if (contractState != ContractState.ExpiredPriceReceived) {
            expiryPrice = _getOraclePrice(expirationTimestamp);
            contractState = ContractState.ExpiredPriceReceived;
        }

        // Get caller's tokens balance and calculate amount of underlying entitled to them.
        FixedPoint.Unsigned memory tokensToRedeem = FixedPoint.Unsigned(
            tokenCurrency.balanceOf(msg.sender)
        );

        FixedPoint.Unsigned memory totalRedeemableCollateral = tokensToRedeem
            .mul(expiryPrice);

        // If the caller is a sponsor with outstanding collateral they are also entitled to their excess collateral after their debt.
        PositionData storage positionData = positions[msg.sender];
        if (positionData.collateral.isGreaterThan(0)) {
            // Calculate the underlying entitled to a token sponsor. This is collateral - debt in underlying.
            FixedPoint.Unsigned memory tokenDebtValueInCollateral = positionData
                .tokensOutstanding
                .mul(expiryPrice);
            FixedPoint.Unsigned memory positionCollateral = positionData
                .collateral;

            // If the debt is greater than the remaining collateral, they cannot redeem anything.
            FixedPoint.Unsigned
                memory positionRedeemableCollateral = tokenDebtValueInCollateral
                    .isLessThan(positionCollateral)
                    ? positionCollateral.sub(tokenDebtValueInCollateral)
                    : FixedPoint.Unsigned(0);

            // Add the number of redeemable tokens for the sponsor to their total redeemable collateral.
            totalRedeemableCollateral = totalRedeemableCollateral.add(
                positionRedeemableCollateral
            );

            // Reset the position state as all the value has been removed after settlement.
            delete positions[msg.sender];
            emit EndedSponsorPosition(msg.sender);
        }

        // Take the min of the remaining collateral and the collateral "owed". If the contract is undercapitalized,
        // the caller will get as much collateral as the contract can pay out.
        FixedPoint.Unsigned memory payout = FixedPoint.min(
            totalPositionCollateral,
            totalRedeemableCollateral
        );

        // Decrement total contract collateral and outstanding debt.
        totalPositionCollateral = totalPositionCollateral.sub(payout);
        amountWithdrawn = payout;
        totalTokensOutstanding = totalTokensOutstanding.sub(tokensToRedeem);

        emit SettleExpiredPosition(
            msg.sender,
            amountWithdrawn.rawValue,
            tokensToRedeem.rawValue
        );

        // Transfer tokens & collateral and burn the redeemed tokens.
        collateralCurrency.safeTransfer(msg.sender, amountWithdrawn.rawValue);
        tokenCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            tokensToRedeem.rawValue
        );
        tokenCurrency.burn(tokensToRedeem.rawValue);
    }

    /****************************************
     *        GLOBAL STATE FUNCTIONS        *
     ****************************************/

    /**
     * @notice Locks contract state in expired and requests oracle price.
     * @dev this function can only be called once the contract is expired and can't be re-called.
     */
    function expire() external onlyPostExpiration onlyOpenState nonReentrant {
        contractState = ContractState.ExpiredPriceRequested;

        _requestOraclePrice_senderPays(expirationTimestamp);

        emit ContractExpired(msg.sender);
    }

    /**
     * @notice Premature contract settlement under emergency circumstances.
     * @dev Only the governor can call this function as they are permissioned within the `FinancialContractAdmin`.
     * Upon emergency shutdown, the contract settlement time is set to the shutdown time. This enables withdrawal
     * to occur via the standard `settleExpired` function. Contract state is set to `ExpiredPriceRequested`
     * which prevents re-entry into this function or the `expire` function. No fees are paid when calling
     * `emergencyShutdown` as the governor who would call the function would also receive the fees.
     */
    function emergencyShutdown()
        external
        onlyPreExpiration
        onlyOpenState
        onlyOwner
    {
        contractState = ContractState.ExpiredPriceRequested;
        // Expiratory time now becomes the current time (emergency shutdown time).
        // Price requested at this time stamp. `settleExpired` can now withdraw at this timestamp.
        uint256 oldExpirationTimestamp = expirationTimestamp;
        expirationTimestamp = block.timestamp;
        _requestOraclePrice_senderPays(expirationTimestamp);

        emit EmergencyShutdown(
            msg.sender,
            oldExpirationTimestamp,
            expirationTimestamp
        );
    }

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

    /**
     * @notice Accessor method to compute a transformed price using the finanicalProductLibrary specified at contract
     * deployment. If no library was provided then no modification to the price is done.
     * @param price input price to be transformed.
     * @param requestTime timestamp the oraclePrice was requested at.
     * @return transformedPrice price with the transformation function applied to it.
     * @dev This method should never revert.
     */

    function transformPrice(
        FixedPoint.Unsigned memory price,
        uint256 requestTime
    ) public view nonReentrantView returns (FixedPoint.Unsigned memory) {
        return _transformPrice(price, requestTime);
    }

    /**
     * @notice Accessor method to compute a transformed price identifier using the finanicalProductLibrary specified
     * at contract deployment. If no library was provided then no modification to the identifier is done.
     * @param requestTime timestamp the identifier is to be used at.
     * @return transformedPrice price with the transformation function applied to it.
     * @dev This method should never revert.
     */
    function transformPriceIdentifier(uint256 requestTime)
        public
        view
        nonReentrantView
        returns (bytes32)
    {
        return _transformPriceIdentifier(requestTime);
    }

    /****************************************
     *          INTERNAL FUNCTIONS          *
     ****************************************/

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

    // Reduces a sponsor's position and global counters by the specified parameters. Handles deleting the entire
    // position if the entire position is being removed. Does not make any external transfers.
    function _reduceSponsorPosition(
        address sponsor,
        FixedPoint.Unsigned memory tokensToRemove,
        FixedPoint.Unsigned memory collateralToRemove,
        FixedPoint.Unsigned memory withdrawalAmountToRemove
    ) internal {
        PositionData storage positionData = _getPositionData(sponsor);

        // If the entire position is being removed, delete it instead.
        if (
            tokensToRemove.isEqual(positionData.tokensOutstanding) &&
            positionData.collateral.isEqual(collateralToRemove)
        ) {
            _deleteSponsorPosition(sponsor);
            return;
        }

        // Decrement the sponsor's collateral and global collateral amounts.
        _decrementCollateralBalances(positionData, collateralToRemove);

        // Ensure that the sponsor will meet the min position size after the reduction.
        FixedPoint.Unsigned memory newTokenCount = positionData
            .tokensOutstanding
            .sub(tokensToRemove);
        require(
            newTokenCount.isGreaterThanOrEqual(minSponsorTokens),
            "Below minimum sponsor position"
        );
        positionData.tokensOutstanding = newTokenCount;

        // Decrement the position's withdrawal amount.
        positionData.withdrawalRequestAmount = positionData
            .withdrawalRequestAmount
            .sub(withdrawalAmountToRemove);

        // Decrement the total outstanding tokens in the overall contract.
        totalTokensOutstanding = totalTokensOutstanding.sub(tokensToRemove);
    }

    // Deletes a sponsor's position and updates global counters. Does not make any external transfers.
    function _deleteSponsorPosition(address sponsor)
        internal
        returns (FixedPoint.Unsigned memory)
    {
        PositionData storage positionToLiquidate = _getPositionData(sponsor);

        FixedPoint.Unsigned
            memory startingGlobalCollateral = totalPositionCollateral;

        // Remove the collateral and outstanding from the overall total position.
        totalPositionCollateral = totalPositionCollateral.sub(
            positionToLiquidate.collateral
        );
        totalTokensOutstanding = totalTokensOutstanding.sub(
            positionToLiquidate.tokensOutstanding
        );

        // Reset the sponsors position to have zero outstanding and collateral.
        delete positions[sponsor];

        emit EndedSponsorPosition(sponsor);

        // Return amount of collateral deleted from position.
        return startingGlobalCollateral.sub(totalPositionCollateral);
    }

    function _getPositionData(address sponsor)
        internal
        view
        onlyCollateralizedPosition(sponsor)
        returns (PositionData storage)
    {
        return positions[sponsor];
    }

    function _getIdentifierWhitelist()
        internal
        view
        returns (IdentifierWhitelistInterface)
    {
        return
            IdentifierWhitelistInterface(
                finder.getImplementationAddress(
                    OracleInterfaces.IdentifierWhitelist
                )
            );
    }

    function _getOptimisticOracle()
        internal
        view
        returns (OptimisticOracleInterface)
    {
        return
            OptimisticOracleInterface(
                finder.getImplementationAddress(
                    OracleInterfaces.OptimisticOracle
                )
            );
    }

    // Requests a price for transformed `priceIdentifier` at `requestedTime` from the Oracle, charging the caller for the OO proposer reward.
    function _requestOraclePrice_senderPays(uint256 requestedTime) internal {
        OptimisticOracleInterface optimisticOracle = _getOptimisticOracle();

        // Pull final fee from sender
        collateralCurrency.safeTransferFrom(
            msg.sender,
            address(this),
            ooReward.rawValue
        );

        // Increase token allowance to enable the optimistic oracle fee payment.
        collateralCurrency.safeIncreaseAllowance(
            address(optimisticOracle),
            ooReward.rawValue
        );
        optimisticOracle.requestPrice(
            _transformPriceIdentifier(requestedTime),
            requestedTime,
            ancillaryData,
            collateralCurrency,
            ooReward.rawValue
        );
    }

    // Fetches a resolved Oracle price from the Oracle. Reverts if the Oracle hasn't resolved for this request.
    function _getOraclePrice(uint256 requestedTime)
        internal
        returns (FixedPoint.Unsigned memory)
    {
        // Create an instance of the oracle and get the price. If the price is not resolved revert.
        OptimisticOracleInterface optimisticOracle = _getOptimisticOracle();
        require(
            optimisticOracle.hasPrice(
                address(this),
                _transformPriceIdentifier(requestedTime),
                requestedTime,
                ancillaryData
            )
        );
        int256 optimisticOraclePrice = optimisticOracle.settleAndGetPrice(
            _transformPriceIdentifier(requestedTime),
            requestedTime,
            ancillaryData
        );

        // For now we don't want to deal with negative prices in positions.
        if (optimisticOraclePrice < 0) {
            optimisticOraclePrice = 0;
        }
        return
            _transformPrice(
                FixedPoint.Unsigned(uint256(optimisticOraclePrice)),
                requestedTime
            );
    }

    // Reset withdrawal request by setting the withdrawal request and withdrawal timestamp to 0.
    function _resetWithdrawalRequest(PositionData storage positionData)
        internal
    {
        positionData.withdrawalRequestAmount = FixedPoint.fromUnscaledUint(0);
        positionData.withdrawalRequestPassTimestamp = 0;
    }

    // Ensure individual and global consistency when increasing collateral balances. Returns the change to the position.
    function _incrementCollateralBalances(
        PositionData storage positionData,
        FixedPoint.Unsigned memory collateralAmount
    ) internal returns (FixedPoint.Unsigned memory) {
        positionData.collateral = positionData.collateral.add(collateralAmount);
        totalPositionCollateral = totalPositionCollateral.add(collateralAmount);
        return collateralAmount;
    }

    // Ensure individual and global consistency when decrementing collateral balances. Returns the change to the
    // position. We elect to return the amount that the global collateral is decreased by, rather than the individual
    // position's collateral, because we need to maintain the invariant that the global collateral is always
    // <= the collateral owned by the contract to avoid reverts on withdrawals. The amount returned = amount withdrawn.
    function _decrementCollateralBalances(
        PositionData storage positionData,
        FixedPoint.Unsigned memory collateralAmount
    ) internal returns (FixedPoint.Unsigned memory) {
        positionData.collateral = positionData.collateral.sub(collateralAmount);
        totalPositionCollateral = totalPositionCollateral.sub(collateralAmount);
        return collateralAmount;
    }

    // Ensure individual and global consistency when decrementing collateral balances. Returns the change to the position.
    // This function is similar to the _decrementCollateralBalances function except this function checks position GCR
    // between the decrements. This ensures that collateral removal will not leave the position undercollateralized.
    function _decrementCollateralBalancesCheckGCR(
        PositionData storage positionData,
        FixedPoint.Unsigned memory collateralAmount
    ) internal returns (FixedPoint.Unsigned memory) {
        positionData.collateral = positionData.collateral.sub(collateralAmount);
        totalPositionCollateral = totalPositionCollateral.sub(collateralAmount);
        require(_checkPositionCollateralization(positionData), "CR below GCR");
        return collateralAmount;
    }

    // These internal functions are supposed to act identically to modifiers, but re-used modifiers
    // unnecessarily increase contract bytecode size.
    // source: https://blog.polymath.network/solidity-tips-and-tricks-to-save-gas-and-reduce-bytecode-size-c44580b218e6
    function _onlyOpenState() internal view {
        require(
            contractState == ContractState.Open,
            "Contract state is not OPEN"
        );
    }

    function _onlyPreExpiration() internal view {
        require(
            block.timestamp < expirationTimestamp,
            "Only callable pre-expiry"
        );
    }

    function _onlyPostExpiration() internal view {
        require(
            block.timestamp >= expirationTimestamp,
            "Only callable post-expiry"
        );
    }

    function _onlyCollateralizedPosition(address sponsor) internal view {
        require(
            positions[sponsor].collateral.isGreaterThan(0),
            "Position has no collateral"
        );
    }

    // Note: This checks whether an already existing position has a pending withdrawal. This cannot be used on the
    // `create` method because it is possible that `create` is called on a new position (i.e. one without any collateral
    // or tokens outstanding) which would fail the `onlyCollateralizedPosition` modifier on `_getPositionData`.
    function _positionHasNoPendingWithdrawal(address sponsor) internal view {
        require(
            _getPositionData(sponsor).withdrawalRequestPassTimestamp == 0,
            "Pending withdrawal"
        );
    }

    /****************************************
     *          PRIVATE FUNCTIONS          *
     ****************************************/

    function _checkPositionCollateralization(PositionData storage positionData)
        private
        view
        returns (bool)
    {
        return
            _checkCollateralization(
                positionData.collateral,
                positionData.tokensOutstanding
            );
    }

    // Checks whether the provided `collateral` and `numTokens` have a collateralization ratio above the global
    // collateralization ratio.
    function _checkCollateralization(
        FixedPoint.Unsigned memory collateral,
        FixedPoint.Unsigned memory numTokens
    ) private view returns (bool) {
        FixedPoint.Unsigned memory global = _getCollateralizationRatio(
            totalPositionCollateral,
            totalTokensOutstanding
        );
        FixedPoint.Unsigned memory thisChange = _getCollateralizationRatio(
            collateral,
            numTokens
        );
        return !global.isGreaterThan(thisChange);
    }

    function _getCollateralizationRatio(
        FixedPoint.Unsigned memory collateral,
        FixedPoint.Unsigned memory numTokens
    ) private pure returns (FixedPoint.Unsigned memory ratio) {
        if (!numTokens.isGreaterThan(0)) {
            return FixedPoint.fromUnscaledUint(0);
        } else {
            return collateral.div(numTokens);
        }
    }

    // IERC20Standard.decimals() will revert if the collateral contract has not implemented the decimals() method,
    // which is possible since the method is only an OPTIONAL method in the ERC20 standard:
    // https://eips.ethereum.org/EIPS/eip-20#methods.
    function _getSyntheticDecimals(address _collateralAddress)
        public
        view
        returns (uint8 decimals)
    {
        try IERC20Standard(_collateralAddress).decimals() returns (
            uint8 _decimals
        ) {
            return _decimals;
        } catch {
            return 18;
        }
    }

    function _transformPrice(
        FixedPoint.Unsigned memory price,
        uint256 requestTime
    ) internal view returns (FixedPoint.Unsigned memory) {
        if (!address(financialProductLibrary).isContract()) return price;
        try financialProductLibrary.transformPrice(price, requestTime) returns (
            FixedPoint.Unsigned memory transformedPrice
        ) {
            return transformedPrice;
        } catch {
            return price;
        }
    }

    function _transformPriceIdentifier(uint256 requestTime)
        internal
        view
        returns (bytes32)
    {
        if (!address(financialProductLibrary).isContract())
            return priceIdentifier;
        try
            financialProductLibrary.transformPriceIdentifier(
                priceIdentifier,
                requestTime
            )
        returns (bytes32 transformedIdentifier) {
            return transformedIdentifier;
        } catch {
            return priceIdentifier;
        }
    }
}

File 15 of 18 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Stores common interface names used throughout the DVM by registration in the Finder.
 */
library OracleInterfaces {
    bytes32 public constant Oracle = "Oracle";
    bytes32 public constant IdentifierWhitelist = "IdentifierWhitelist";
    bytes32 public constant Store = "Store";
    bytes32 public constant FinancialContractsAdmin = "FinancialContractsAdmin";
    bytes32 public constant Registry = "Registry";
    bytes32 public constant CollateralWhitelist = "CollateralWhitelist";
    bytes32 public constant OptimisticOracle = "OptimisticOracle";
    bytes32 public constant Bridge = "Bridge";
    bytes32 public constant GenericHandler = "GenericHandler";
    bytes32 public constant SkinnyOptimisticOracle = "SkinnyOptimisticOracle";
    bytes32 public constant ChildMessenger = "ChildMessenger";
    bytes32 public constant OracleHub = "OracleHub";
    bytes32 public constant OracleSpoke = "OracleSpoke";
}

/**
 * @title Commonly re-used values for contracts associated with the OptimisticOracle.
 */
library OptimisticOracleConstraints {
    // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.
    // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible
    // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which
    // refuses to accept a price request made with ancillary data length over a certain size.
    uint256 public constant ancillaryBytesLimit = 8192;
}

File 16 of 18 : FinderInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Provides addresses of the live contracts implementing certain interfaces.
 * @dev Examples are the Oracle or Store interfaces.
 */
interface FinderInterface {
    /**
     * @notice Updates the address of the contract that implements `interfaceName`.
     * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.
     * @param implementationAddress address of the deployed contract that implements the interface.
     */
    function changeImplementationAddress(
        bytes32 interfaceName,
        address implementationAddress
    ) external;

    /**
     * @notice Gets the address of the contract that implements the given `interfaceName`.
     * @param interfaceName queried interface.
     * @return implementationAddress address of the deployed contract that implements the interface.
     */
    function getImplementationAddress(bytes32 interfaceName)
        external
        view
        returns (address);
}

File 17 of 18 : IdentifierWhitelistInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.
 */
interface IdentifierWhitelistInterface {
    /**
     * @notice Adds the provided identifier as a supported identifier.
     * @dev Price requests using this identifier will succeed after this call.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     */
    function addSupportedIdentifier(bytes32 identifier) external;

    /**
     * @notice Removes the identifier from the whitelist.
     * @dev Price requests using this identifier will no longer succeed after this call.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     */
    function removeSupportedIdentifier(bytes32 identifier) external;

    /**
     * @notice Checks whether an identifier is on the whitelist.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     * @return bool if the identifier is supported (or not).
     */
    function isIdentifierSupported(bytes32 identifier)
        external
        view
        returns (bool);
}

File 18 of 18 : OptimisticOracleInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./FinderInterface.sol";

/**
 * @title Financial contract facing Oracle interface.
 * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
 */
abstract contract OptimisticOracleInterface {
    event RequestPrice(
        address indexed requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes ancillaryData,
        address currency,
        uint256 reward,
        uint256 finalFee
    );
    event ProposePrice(
        address indexed requester,
        address indexed proposer,
        bytes32 identifier,
        uint256 timestamp,
        bytes ancillaryData,
        int256 proposedPrice,
        uint256 expirationTimestamp,
        address currency
    );
    event DisputePrice(
        address indexed requester,
        address indexed proposer,
        address indexed disputer,
        bytes32 identifier,
        uint256 timestamp,
        bytes ancillaryData,
        int256 proposedPrice
    );
    event Settle(
        address indexed requester,
        address indexed proposer,
        address indexed disputer,
        bytes32 identifier,
        uint256 timestamp,
        bytes ancillaryData,
        int256 price,
        uint256 payout
    );

    // Struct representing the state of a price request.
    enum State {
        Invalid, // Never requested.
        Requested, // Requested, no other actions taken.
        Proposed, // Proposed, but not expired or disputed yet.
        Expired, // Proposed, not disputed, past liveness.
        Disputed, // Disputed, but no DVM price returned yet.
        Resolved, // Disputed and DVM price is available.
        Settled // Final price has been set in the contract (can get here from Expired or Resolved).
    }

    // Struct representing a price request.
    struct Request {
        address proposer; // Address of the proposer.
        address disputer; // Address of the disputer.
        IERC20 currency; // ERC20 token used to pay rewards and fees.
        bool settled; // True if the request is settled.
        bool refundOnDispute; // True if the requester should be refunded their reward on dispute.
        int256 proposedPrice; // Price that the proposer submitted.
        int256 resolvedPrice; // Price resolved once the request is settled.
        uint256 expirationTime; // Time at which the request auto-settles without a dispute.
        uint256 reward; // Amount of the currency to pay to the proposer on settlement.
        uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.
        uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.
        uint256 customLiveness; // Custom liveness value set by the requester.
    }

    // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible
    // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses
    // to accept a price request made with ancillary data length over a certain size.
    uint256 public constant ancillaryBytesLimit = 8192;

    function defaultLiveness() external view virtual returns (uint256);

    function finder() external view virtual returns (FinderInterface);

    function getCurrentTime() external view virtual returns (uint256);

    // Note: this is required so that typechain generates a return value with named fields.
    mapping(bytes32 => Request) public requests;

    /**
     * @notice Requests a new price.
     * @param identifier price identifier being requested.
     * @param timestamp timestamp of the price being requested.
     * @param ancillaryData ancillary data representing additional args being passed with the price request.
     * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
     * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
     *               which could make sense if the contract requests and proposes the value in the same call or
     *               provides its own reward system.
     * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.
     * This can be changed with a subsequent call to setBond().
     */
    function requestPrice(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        IERC20 currency,
        uint256 reward
    ) external virtual returns (uint256 totalBond);

    /**
     * @notice Set the proposal bond associated with a price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @param bond custom bond amount to set.
     * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be
     * changed again with a subsequent call to setBond().
     */
    function setBond(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        uint256 bond
    ) external virtual returns (uint256 totalBond);

    /**
     * @notice Sets the request to refund the reward if the proposal is disputed. This can help to "hedge" the caller
     * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's
     * bond, so there is still profit to be made even if the reward is refunded.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     */
    function setRefundOnDispute(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) external virtual;

    /**
     * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before
     * being auto-resolved.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @param customLiveness new custom liveness.
     */
    function setCustomLiveness(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        uint256 customLiveness
    ) external virtual;

    /**
     * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come
     * from this proposal. However, any bonds are pulled from the caller.
     * @param proposer address to set as the proposer.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @param proposedPrice price being proposed.
     * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
     * the proposer once settled if the proposal is correct.
     */
    function proposePriceFor(
        address proposer,
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        int256 proposedPrice
    ) public virtual returns (uint256 totalBond);

    /**
     * @notice Proposes a price value for an existing price request.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @param proposedPrice price being proposed.
     * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to
     * the proposer once settled if the proposal is correct.
     */
    function proposePrice(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        int256 proposedPrice
    ) external virtual returns (uint256 totalBond);

    /**
     * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will
     * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.
     * @param disputer address to set as the disputer.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
     * the disputer once settled if the dispute was value (the proposal was incorrect).
     */
    function disputePriceFor(
        address disputer,
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) public virtual returns (uint256 totalBond);

    /**
     * @notice Disputes a price value for an existing price request with an active proposal.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to
     * the disputer once settled if the dispute was valid (the proposal was incorrect).
     */
    function disputePrice(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) external virtual returns (uint256 totalBond);

    /**
     * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled
     * or settleable. Note: this method is not view so that this call may actually settle the price request if it
     * hasn't been settled.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return resolved price.
     */
    function settleAndGetPrice(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) external virtual returns (int256);

    /**
     * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes
     * the returned bonds as well as additional rewards.
     */
    function settle(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) external virtual returns (uint256 payout);

    /**
     * @notice Gets the current data structure containing all information about a price request.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return the Request data structure.
     */
    function getRequest(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) public view virtual returns (Request memory);

    /**
     * @notice Returns the state of a price request.
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return the State enum value.
     */
    function getState(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) public view virtual returns (State);

    /**
     * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).
     * @param requester sender of the initial price request.
     * @param identifier price identifier to identify the existing request.
     * @param timestamp timestamp to identify the existing request.
     * @param ancillaryData ancillary data of the price being requested.
     * @return true if price has resolved or settled, false otherwise.
     */
    function hasPrice(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData
    ) public view virtual returns (bool);

    function stampAncillaryData(bytes memory ancillaryData, address requester)
        public
        view
        virtual
        returns (bytes memory);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"components":[{"internalType":"uint256","name":"expirationTimestamp","type":"uint256"},{"internalType":"uint256","name":"withdrawalLiveness","type":"uint256"},{"internalType":"address","name":"collateralAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"finderAddress","type":"address"},{"internalType":"address","name":"financialProductLibraryAddress","type":"address"},{"internalType":"bytes32","name":"priceFeedIdentifier","type":"bytes32"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"minSponsorTokens","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"ooReward","type":"tuple"},{"internalType":"uint256","name":"liquidationLiveness","type":"uint256"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralRequirement","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"disputeBondPercentage","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"sponsorDisputeRewardPercentage","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"disputerDisputeRewardPercentage","type":"tuple"},{"internalType":"address","name":"owner","type":"address"}],"internalType":"struct Liquidatable.ConstructorParams","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"ContractExpired","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"disputer","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidationId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"disputeSucceeded","type":"bool"}],"name":"DisputeSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"originalExpirationTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shutdownTimestamp","type":"uint256"}],"name":"EmergencyShutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"}],"name":"EndedSponsorPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"uint256","name":"liquidationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensOutstanding","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralAfterWithdrawals","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationTime","type":"uint256"}],"name":"LiquidationCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"disputer","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"disputeBondAmount","type":"uint256"}],"name":"LiquidationDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"paidToLiquidator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidToDisputer","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidToSponsor","type":"uint256"},{"indexed":true,"internalType":"enum Liquidatable.Status","name":"liquidationStatus","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"settlementPrice","type":"uint256"}],"name":"LiquidationWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"}],"name":"NewSponsor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"PositionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"numTokensRepaid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newTokenCount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSponsor","type":"address"}],"name":"RequestTransferPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSponsor","type":"address"}],"name":"RequestTransferPositionCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSponsor","type":"address"},{"indexed":true,"internalType":"address","name":"newSponsor","type":"address"}],"name":"RequestTransferPositionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"RequestWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"RequestWithdrawalCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"RequestWithdrawalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralReturned","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokensBurned","type":"uint256"}],"name":"SettleExpiredPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"_collateralAddress","type":"address"}],"name":"_getSyntheticDecimals","outputs":[{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ancillaryData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelTransferPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateralCurrency","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralRequirement","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractState","outputs":[{"internalType":"enum PricelessPositionManager.ContractState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"numTokens","type":"tuple"}],"name":"create","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sponsor","type":"address"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"minCollateralPerToken","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"maxCollateralPerToken","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"maxTokensToLiquidate","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"createLiquidation","outputs":[{"internalType":"uint256","name":"liquidationId","type":"uint256"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"tokensLiquidated","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralAmount","type":"tuple"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sponsor","type":"address"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralAmount","type":"tuple"}],"name":"depositTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationId","type":"uint256"},{"internalType":"address","name":"sponsor","type":"address"}],"name":"dispute","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"totalPaid","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disputeBondPercentage","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputerDisputeRewardPercentage","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"expirationTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"expire","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"expiryPrice","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"financialProductLibrary","outputs":[{"internalType":"contract FinancialProductLibrary","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finder","outputs":[{"internalType":"contract FinderInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sponsor","type":"address"}],"name":"getLiquidations","outputs":[{"components":[{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"enum Liquidatable.Status","name":"state","type":"uint8"},{"internalType":"uint256","name":"liquidationTime","type":"uint256"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"tokensOutstanding","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"lockedCollateral","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"lockedCollateralAfterWithdrawals","type":"tuple"},{"internalType":"address","name":"disputer","type":"address"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"settlementPrice","type":"tuple"}],"internalType":"struct Liquidatable.LiquidationData[]","name":"liquidationData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationCollateral","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationLiveness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"liquidations","outputs":[{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"enum Liquidatable.Status","name":"state","type":"uint8"},{"internalType":"uint256","name":"liquidationTime","type":"uint256"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"tokensOutstanding","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"lockedCollateral","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"lockedCollateralAfterWithdrawals","type":"tuple"},{"internalType":"address","name":"disputer","type":"address"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"settlementPrice","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minSponsorTokens","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ooReward","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"positions","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"tokensOutstanding","type":"tuple"},{"internalType":"uint256","name":"withdrawalRequestPassTimestamp","type":"uint256"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"withdrawalRequestAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateral","type":"tuple"},{"internalType":"uint256","name":"transferPositionRequestPassTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceIdentifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"numTokens","type":"tuple"}],"name":"redeem","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"amountWithdrawn","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"numTokens","type":"tuple"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestTransferPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralAmount","type":"tuple"}],"name":"requestWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleExpired","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"amountWithdrawn","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sponsorDisputeRewardPercentage","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenCurrency","outputs":[{"internalType":"contract ExpandedIERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPositionCollateral","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensOutstanding","outputs":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSponsorAddress","type":"address"}],"name":"transferPositionPassedRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"price","type":"tuple"}],"name":"transformCollateralRequirement","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"price","type":"tuple"},{"internalType":"uint256","name":"requestTime","type":"uint256"}],"name":"transformPrice","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestTime","type":"uint256"}],"name":"transformPriceIdentifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"collateralAmount","type":"tuple"}],"name":"withdraw","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"amountWithdrawn","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationId","type":"uint256"},{"internalType":"address","name":"sponsor","type":"address"}],"name":"withdrawLiquidation","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"payToSponsor","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"payToLiquidator","type":"tuple"},{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"payToDisputer","type":"tuple"}],"internalType":"struct Liquidatable.RewardsData","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPassedRequest","outputs":[{"components":[{"internalType":"uint256","name":"rawValue","type":"uint256"}],"internalType":"struct FixedPoint.Unsigned","name":"amountWithdrawn","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalLiveness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b5060405162004c2b38038062004c2b833981016040819052620000349162000601565b8051602082015160408301516060840151608085015160c086015161010087015161012088015160a089015160e08a01516101e08b01516000805460ff191660011790558b9a999897969594939291906200008e620002d0565b6200009e6000805460ff19169055565b600680546001600160a01b0319166001600160a01b038916179055428b11620000c657600080fd5b620000d062000329565b6001600160a01b03166390978d1b876040518263ffffffff1660e01b8152600401620000fe91815260200190565b602060405180830381865afa1580156200011c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200014291906200078f565b6200014c57600080fd5b60098b9055600a8a9055600480546001600160a01b03808b166001600160a01b03199283161790925560058054928c16929091169190911790558451600b558351600d5560078690556008620001a3838262000842565b50600e80546001600160a01b038084166001600160a01b031992831617909255600f805492861692909116919091179055620001e76000805460ff19166001179055565b505050505050505050505062000202620002d060201b60201c565b620002126000805460ff19169055565b620002326001826101600151620003be60201b620027a61790919060201c565b6200023c57600080fd5b6200027a600162000266836101c00151846101a00151620003d860201b620027bd1790919060201c565b6200041d60201b620027f01790919060201c565b6200028457600080fd5b61014081015160125561016081015151601355610180810151516014556101a0810151516015556101c081015151601655620002c86000805460ff19166001179055565b50506200097a565b60005460ff16620003275760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640160405180910390fd5b565b6006546040516302abf57960e61b81527f4964656e74696669657257686974656c6973740000000000000000000000000060048201526000916001600160a01b03169063aafd5e4090602401602060405180830381865afa15801562000393573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003b991906200090e565b905090565b6000620003cb8262000436565b5183511190505b92915050565b604080516020810190915260008152604051806020016040528062000414846000015186600001516200047a60201b620028071790919060201c565b90529392505050565b60006200042a8262000436565b51835110905092915050565b604080516020810190915260008152604051806020016040528062000472670de0b6b3a7640000856200048f60201b620028131790919060201c565b905292915050565b600062000488828462000942565b9392505050565b600062000488828462000958565b634e487b7160e01b600052604160045260246000fd5b60405161020081016001600160401b0381118282101715620004d957620004d96200049d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200050a576200050a6200049d565b604052919050565b80516001600160a01b03811681146200052a57600080fd5b919050565b600082601f8301126200054157600080fd5b81516001600160401b038111156200055d576200055d6200049d565b602062000573601f8301601f19168201620004df565b82815285828487010111156200058857600080fd5b60005b83811015620005a85785810183015182820184015282016200058b565b506000928101909101919091529392505050565b600060208284031215620005cf57600080fd5b604051602081016001600160401b0381118282101715620005f457620005f46200049d565b6040529151825250919050565b6000602082840312156200061457600080fd5b81516001600160401b03808211156200062c57600080fd5b9083019061020082860312156200064257600080fd5b6200064c620004b3565b8251815260208301516020820152620006686040840162000512565b60408201526200067b6060840162000512565b60608201526200068e6080840162000512565b6080820152620006a160a0840162000512565b60a082015260c083015160c082015260e083015182811115620006c357600080fd5b620006d1878286016200052f565b60e0830152506101009150620006ea86838501620005bc565b8282015261012091506200070186838501620005bc565b828201526101409150818301518282015261016091506200072586838501620005bc565b8282015261018091506200073c86838501620005bc565b828201526101a091506200075386838501620005bc565b828201526101c091506200076a86838501620005bc565b828201526101e091506200078082840162000512565b91810191909152949350505050565b600060208284031215620007a257600080fd5b815180151581146200048857600080fd5b600181811c90821680620007c857607f821691505b602082108103620007e957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200083d57600081815260208120601f850160051c81016020861015620008185750805b601f850160051c820191505b81811015620008395782815560010162000824565b5050505b505050565b81516001600160401b038111156200085e576200085e6200049d565b62000876816200086f8454620007b3565b84620007ef565b602080601f831160018114620008ae5760008415620008955750858301515b600019600386901b1c1916600185901b17855562000839565b600085815260208120601f198616915b82811015620008df57888601518255948401946001909101908401620008be565b5085821015620008fe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200092157600080fd5b620004888262000512565b634e487b7160e01b600052601160045260246000fd5b80820180821115620003d257620003d26200092c565b60008160001904831182151516156200097557620009756200092c565b500290565b6142a1806200098a6000396000f3fe608060405234801561001057600080fd5b50600436106102955760003560e01c806362b5f7f5116101675780639ff4dea8116100ce578063d1e92c1111610087578063d1e92c1114610629578063e3c0f9cb1461063c578063edfa9a9b14610646578063f0391daf14610650578063f2fde38b1461065a578063fcccedc71461066d57600080fd5b80639ff4dea8146105bf578063a1c4d1e7146105c8578063a765fbea146105e8578063b795f0d4146105fb578063b9a3c84c14610603578063bc1216301461061657600080fd5b806385209ee01161012057806385209ee01461055e5780638da5cb5b1461057d57806392120aec146105905780639375f0e91461059a57806397523661146105ad5780639f43ddd2146105b657600080fd5b806362b5f7f5146104fe57806365599057146105115780636ba2f992146105265780637048594b1461053957806379599f961461054c5780637e398c221461055457600080fd5b80633403c2fc1161020b5780634ead6e51116101c45780634ead6e51146103ef5780634f8c48471461041457806355f575101461043c5780635617151c146104c55780635aa266c9146104d85780635f1af1ca146104eb57600080fd5b80633403c2fc14610380578063360598e11461038857806336980f58146103c05780633ee7a5ce146103c857806343e4771b146103db57806348e30c3f146103e557600080fd5b8063197f78481161025d578063197f784814610323578063226112801461033657806325ed4dd81461033e5780632d5436cf146103655780632e154f2e1461036e57806333a46ca21461037857600080fd5b8063081b314e1461029a5780630c9229ca146102b75780630de15fd9146102c15780630ff49b90146102ec57806318928a0c1461030e575b600080fd5b6015546102a49081565b6040519081526020015b60405180910390f35b6002546102a49081565b6005546102d4906001600160a01b031681565b6040516001600160a01b0390911681526020016102ae565b6102ff6102fa366004613bd9565b610675565b604051905181526020016102ae565b61032161031c366004613c19565b61069f565b005b6102ff610331366004613c4f565b61074f565b61032161076f565b61035161034c366004613c7d565b6107e1565b6040805192835290516020830152016102ae565b6102a460125481565b6014546102a49081565b6102ff610d6a565b610321610e8f565b61039b610396366004613cde565b610f5c565b60408051825151815260208084015151908201529181015151908201526060016102ae565b610321611450565b6102ff6103d6366004613c4f565b6114e9565b6003546102a49081565b6013546102a49081565b6104026103fd366004613d0e565b6115a1565b60405160ff90911681526020016102ae565b610427610422366004613d32565b611609565b6040516102ae99989796959493929190613d7a565b61049861044a366004613d0e565b60016020818152600092835260409283902083518083018552815481529281015484518084018652600283015481528551938401909552600382015483526004909101549293909290919085565b6040805195518652602086019490945291519284019290925290516060830152608082015260a0016102ae565b6103216104d3366004613d0e565b6116ae565b6103216104e6366004613c4f565b61184c565b6102ff6104f9366004613c4f565b6119ad565b6102a461050c366004613dda565b611bbf565b610519611bd2565b6040516102ae9190613e43565b610321610534366004613e56565b611c60565b6004546102d4906001600160a01b031681565b610321611f00565b6016546102a49081565b60005461057090610100900460ff1681565b6040516102ae9190613e73565b600e546102d4906001600160a01b031681565b600b546102a49081565b600f546102d4906001600160a01b031681565b6102a460075481565b6102a460095481565b6102a4600a5481565b6105db6105d6366004613d0e565b611f6e565b6040516102ae9190613e8d565b6102ff6105f6366004613cde565b6120b1565b610321612206565b6006546102d4906001600160a01b031681565b610321610624366004613c4f565b612277565b610321610637366004613c4f565b612346565b6011546102a49081565b600c546102a49081565b600d546102a49081565b610321610668366004613d0e565b612353565b6102ff612406565b60408051602081019091526000815261068c61281f565b6106968383612871565b90505b92915050565b6106a7612915565b816106b181612966565b6106b961281f565b6106c16129b5565b6106cc8260006127a6565b6106d557600080fd5b60006106e0846129c1565b90506106ec81846129e9565b5082516040516001600160a01b038616907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90600090a38251600554610741916001600160a01b039091169033903090612a41565b5061074a612ab2565b505050565b60408051602081019091526000815261076661281f565b61069982612ac1565b61077761281f565b61077f6129b5565b600061078a336129c1565b9050806001015460000361079d57600080fd5b600281015460405133907f74d8a3658feb89d1a5c335229bbbfc3bbcfaf492769feb7aa4cd2d92efeaf69190600090a36107d681612b7c565b506107df612ab2565b565b60006107f96040518060200160405280600081525090565b610801612915565b61080961281f565b6108116129b5565b8242111561085d5760405162461bcd60e51b81526020600482015260146024820152734d696e656420616674657220646561646c696e6560601b60448201526064015b60405180910390fd5b6000610868886129c1565b905061089061087c36879003870187613c4f565b604080516020810190915283548152612b96565b915061089d8260006127a6565b6108a657600080fd5b60408051602081019091526003820154815260006108c381612bbb565b6040805160208101909152600285015490819052835191925011610901576040805160208101909152600284015481526108fe908390612bf0565b90505b6040805160208101909152835481526109368261092d83610927368e90038e018e613c4f565b90612c1a565b90519051101590565b6109825760405162461bcd60e51b815260206004820152601e60248201527f4352206973206d6f7265207468616e206d6178206c69712e20707269636500006044820152606401610854565b6109a28261099983610927368f90038f018f613c4f565b90519051111590565b6109ee5760405162461bcd60e51b815260206004820152601e60248201527f4352206973206c657373207468616e206d696e206c69712e20707269636500006044820152606401610854565b50604080516020810190915260008152604080516020810190915260008152604080516020810190915285548152600090610a2a908890612c57565b9050610a368582612c1a565b9250610a428482612c1a565b604080516020810190915260028801548152909250600090610a649083612c1a565b9050610a728e898684612c93565b50506040805160208082018352600d54825282519081019092526011548252610aa591610a9f90856127bd565b906127bd565b516011556001600160a01b038c1660008181526010602090815260409182902080548351610120810185529485523392850192909252909950919081016001815260200142815260200188815260200184815260200183815260200160006001600160a01b03168152602001610b1b6000612bbb565b90528154600181810184556000938452602093849020835160089093020180546001600160a01b039384166001600160a01b0319918216178255948401519181018054929093169482168517835560408401519394909392916001600160a81b03191617600160a01b836004811115610b9657610b96613d50565b021790555060608201516002820155608082015151600382015560a082015151600482015560c082015151600582015560e08201516006820180546001600160a01b0319166001600160a01b0390921691909117905561010090910151516007909101556040805160208101909152600b548152600186015415801590610c205750428660010154115b8015610c2e57508051875110155b15610c4757600a54610c41904290612807565b60018701555b87336001600160a01b03168e6001600160a01b03167f39b4371645b4132767fd76a1aad3108ff95c20d7b687b24d171555f5459a75978a600001518760000151876000015142604051610cb3949392919093845260208401929092526040830152606082015260800190565b60405180910390a48651600454610cd9916001600160a01b039091169033903090612a41565b600480548851604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b158015610d1d57600080fd5b505af1158015610d31573d6000803e3d6000fd5b5050600d54600554610d5293506001600160a01b0316915033903090612a41565b505050505050610d60612ab2565b9550959350505050565b604080516020810190915260008152610d81612915565b610d8961281f565b610d916129b5565b6000610d9c336129c1565b90508060010154600014158015610db7575042816001015411155b610dc057600080fd5b60408051602080820183526000825282518082018452600385015481528351918201909352600284015490819052915190911115610e105750604080516020810190915260038201548152610e24565b506040805160208101909152600282015481525b610e2e8282612d94565b9250610e3982612b7c565b8251600554610e55916001600160a01b03909116903390612de2565b825160405133907fc86c3298cb79f486674dca87d9247e88b76146160e7d412cc59b26b14c358a6890600090a35050610e8c612ab2565b90565b610e97612915565b610e9f612e12565b600e546001600160a01b03163314610ef35760405162461bcd60e51b815260206004820152601760248201527631b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606401610854565b6000805461ff00191661010017905560098054429182905590610f1590612e7c565b60095460405133917fd39eeb7157d9c446579a0893ecf9ecd87d1f466cdb270c6a189cf38ca1e30f4891610f5191858252602082015260400190565b60405180910390a250565b610f996040805160808101825260006060820181815282528251602080820185528282528084019190915283519081018452908152909182015290565b8282610fa58282612f56565b610fad61281f565b610fb56129b5565b6000610fc18587613005565b9050610fcd86866130dd565b604080516020808201835260078401548252825190810190925260038301548252600091610ffa91612c1a565b6040805160208101909152601654815290915060009061101a9083612c1a565b6040805160208101909152601554815290915060009061103a9084612c1a565b604080516020808201835260145482528251908101909252600487015482529192506000916110699190612c1a565b90506110a86040805160808101825260006060820181815282528251602080820185528282528084019190915283519081018452908152909182015290565b60036001870154600160a01b900460ff1660048111156110ca576110ca613d50565b03611201576040805160208101909152600d5481526110ed90610a9f86856127bd565b60408083019190915280516020810190915260048701548152611116908490610a9f9088612bf0565b815261112c846111268786612bf0565b90612bf0565b6020808301829052604080519182019052601154815261114b91612bf0565b5160118190558151604080516020810190915291825261116b9190612bf0565b51601181905560408083015181516020810190925291815261118c91612bf0565b5160115560068601546040820151516005546111b6926001600160a01b0391821692911690612de2565b60018601546020820151516005546111dc926001600160a01b0391821692911690612de2565b85548151516005546111fc926001600160a01b0391821692911690612de2565b611336565b60046001870154600160a01b900460ff16600481111561122357611223613d50565b0361129e576040805160208082018352600d54825282519081019092526004880154825261125591610a9f90856127bd565b6020808301829052604080519182019052601154815261127491612bf0565b5160115560018601546020820151516005546111fc926001600160a01b0391821692911690612de2565b600180870154600160a01b900460ff1660048111156112bf576112bf613d50565b03611336576040805160208082018352600d5482528251908101909252600488015482526112ed91906127bd565b6020808301829052604080519182019052601154815261130c91612bf0565b516011556001860154602082015151600554611336926001600160a01b0391821692911690612de2565b6001860154600160a01b900460ff16600481111561135657611356613d50565b602082810151516040808501515185515160078c015483519485529484019190915290820152606081019190915233907fb479588a37dc7f6bac1c91587fcfc539cac4949cf26bb536ad9c8d061f00f50d9060800160405180910390a36001600160a01b038a16600090815260106020526040902080548c9081106113dd576113dd613f47565b60009182526020822060089091020180546001600160a01b031990811682556001820180546001600160a81b03191690556002820183905560038201839055600482018390556005820183905560068201805490911690556007015597505050505050611448612ab2565b505092915050565b611458612915565b61146061281f565b6114686129b5565b6000611473336129c1565b9050806004015460001461148657600080fd5b600061149d600a544261280790919063ffffffff16565b905060095481106114ad57600080fd5b6004820181905560405133907fbf457c80c8bf299d5c48272c4c1168bf87b33d83b13f0ab9aac332ce1161ed1e90600090a250506107df612ab2565b604080516020810190915260008152611500612915565b3361150a81612966565b61151261281f565b61151a6129b5565b6115258360006127a6565b61152e57600080fd5b6000611539336129c1565b9050611545818561323c565b80516040519194509033907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6590600090a38251600554611592916001600160a01b03909116903390612de2565b5061159b612ab2565b50919050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156115fd575060408051601f3d908101601f191682019092526115fa91810190613f5d565b60015b61069957506012919050565b6010602052816000526040600020818154811061162557600080fd5b600091825260209182902060089190910201805460018201546002830154604080518087018252600386015481528151808801835260048701548152825180890184526005880154815260068801548451998a0190945260079097015488526001600160a01b0395861699508585169850600160a01b90940460ff169692959094909291169089565b6116b6612915565b336116c081612966565b6116c861281f565b6116d06129b5565b6117116116dd6000612bbb565b6001600160a01b03841660009081526001602090815260409182902082519182019092526003909101548152905190511490565b61171a57600080fd5b6000611725336129c1565b90508060040154600014158015611740575042816004015411155b61174957600080fd5b600060048083018281556001600160a01b038616808452600160208190526040808620875481558288015481840155600280890154818301556003808a0154818401559554918701919091553380885282882088815593840188905590830187905593820186905593018490559151919290917ff1a2dcf23621f1a96185c79d39a5776b5ba3dadbea70c5aa86d84c17c7e9418e9190a36040516001600160a01b038416907ff60993fa76f94c9e0a803526ee6e1314814ed4d2b0d223febf1436b36897fb3790600090a260405133907fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc28290600090a250611848612ab2565b5050565b611854612915565b3361185e81612966565b61186661281f565b61186e6129b5565b6000611879336129c1565b60408051602081019091528154908190528451919250101561189a57600080fd5b6040805160208101909152815481526000906118b69085612bf0565b6040805160208101909152600b5490819052815191925011156118d857600080fd5b80518255604080516020810190915260025481526118f69085612bf0565b516002558051845160405133907f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d090600090a48351600454611947916001600160a01b039091169033903090612a41565b600480548551604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b15801561198b57600080fd5b505af115801561199f573d6000803e3d6000fd5b505050505050611848612ab2565b604080516020810190915260008152336119c681612966565b6119ce61281f565b6119d66129b5565b60006119e1336129c1565b604080516020810190915281549081905285519192501015611a0257600080fd5b604080516020810190915281548152600090611a1f908690612c57565b604080516020810190915260038401548152909150600090611a42908390612c1a565b6040805160208101909152845490819052875191925003611a6d57611a66336132d2565b9450611aef565b611a778382612d94565b604080516020810190915284548152909550600090611a969088612bf0565b6040805160208101909152600b549081905281519192501115611acb5760405162461bcd60e51b815260040161085490613f80565b8051845560408051602081019091526002548152611ae99088612bf0565b51600255505b8551855160405133907fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92990600090a48451600554611b3a916001600160a01b03909116903390612de2565b8551600454611b58916001600160a01b039091169033903090612a41565b600480548751604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b158015611b9c57600080fd5b505af1158015611bb0573d6000803e3d6000fd5b5050505050505061159b612ab2565b6000611bc961281f565b610699826133d4565b60088054611bdf90613fb7565b80601f0160208091040260200160405190810160405280929190818152602001828054611c0b90613fb7565b8015611c585780601f10611c2d57610100808354040283529160200191611c58565b820191906000526020600020905b815481529060010190602001808311611c3b57829003601f168201915b505050505081565b611c68612915565b611c7061281f565b611c786129b5565b33600090815260016020908152604091829020825191820190925260038201548152611cc690611ca890856127bd565b604080516020810190915283548152611cc190856127bd565b613471565b80611cd65750611cd68383613471565b611d225760405162461bcd60e51b815260206004820152601760248201527f496e73756666696369656e7420636f6c6c61746572616c0000000000000000006044820152606401610854565b600181015415611d695760405162461bcd60e51b815260206004820152601260248201527114195b991a5b99c81dda5d1a191c985dd85b60721b6044820152606401610854565b604080516020810190915281548152611d839060006134c2565b15611de6576040805160208101909152600b549081905282511015611dba5760405162461bcd60e51b815260040161085490613f80565b60405133907ff60993fa76f94c9e0a803526ee6e1314814ed4d2b0d223febf1436b36897fb3790600090a25b611df081846129e9565b50604080516020810190915281548152611e0a90836127bd565b51815560408051602081019091526002548152611e2790836127bd565b516002558151835160405133907f4b82aa16e071a61de1a6b9aeec9edab0356331f8122c78683b469ac8e685dabc90600090a48251600554611e78916001600160a01b039091169033903090612a41565b6004805483516040516340c10f1960e01b8152339381019390935260248301526001600160a01b0316906340c10f19906044016020604051808303816000875af1158015611eca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eee9190613feb565b611ef757600080fd5b50611848612ab2565b611f086134d9565b611f10612e12565b611f1861281f565b611f206129b5565b6000805461ff001916610100179055600954611f3b90612e7c565b60405133907f18600820405d6cf356e3556301762ca32395e72d8c81494fa344835c9da3633d90600090a26107df612ab2565b6060611f7861281f565b6001600160a01b038216600090815260106020908152604080832080548251818502810185019093528083529193909284015b828210156120a657600084815260209081902060408051610120810182526008860290920180546001600160a01b039081168452600182015490811694840194909452919290830190600160a01b900460ff16600481111561200f5761200f613d50565b600481111561202057612020613d50565b815260028201546020808301919091526040805180830182526003850154815281840152805180830182526004850154815260608401528051808301825260058501548152608084015260068401546001600160a01b031660a08401528051808301909152600790930154835260c0909101919091529082526001929092019101611fab565b505050509050919050565b60408051602081019091526000815282826120cc828261352b565b6120d461281f565b6120dc6129b5565b60006120e88587613005565b604080516020808201835260145482528251908101909252600483015482529192506000916121179190612c1a565b6040805160208101909152601154815290915061213490826127bd565b5160115560018201805460ff60a01b1916600160a11b1790556006820180546001600160a01b03191633179055600282015461216f90612e7c565b60018201548151604080518a8152602081019290925233926001600160a01b0390811692908a16917fcaca181ccad7979cf36ed4fc921e496001ab5264608f0fac7007ae1b43d36102910160405180910390a46040805160208101909152600d5481526121dd9082906127bd565b81516005549196506121fc916001600160a01b03169033903090612a41565b5050611448612ab2565b61220e612915565b61221661281f565b61221e6129b5565b6000612229336129c1565b9050806004015460000361223c57600080fd5b60405133907f2e5702420c76e041698ad7ba57a9ff5cadccf647ea8d96e6007a40b5b2662f5690600090a260006004909101556107df612ab2565b61227f612915565b3361228981612966565b61229161281f565b6122996129b5565b60006122a4336129c1565b90506122b18360006127a6565b80156122d157506040805160208101909152600382015490819052835111155b6122da57600080fd5b60006122f1600a544261280790919063ffffffff16565b9050600954811061230157600080fd5b6001820181905583516002830181905560405133907fd33b726e11d2c5d38e6702b16613df0160a07f7ba5185455ee3c45d0494fab1190600090a35050611848612ab2565b612350338261069f565b50565b600e546001600160a01b031633146123a75760405162461bcd60e51b815260206004820152601760248201527631b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606401610854565b6001600160a01b0381166123fd5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610854565b612350816135ba565b60408051602081019091526000815261241d6134d9565b61242561281f565b61242d6129b5565b60008054610100900460ff16600281111561244a5761244a613d50565b0361248c5760405162461bcd60e51b81526020600482015260126024820152712ab732bc3834b932b2103837b9b4ba34b7b760711b6044820152606401610854565b6002600054610100900460ff1660028111156124aa576124aa613d50565b146124ce576124ba60095461360c565b51600c556000805461ff0019166102001790555b6040805160208101918290526004546370a0823160e01b90925233602482015260009181906001600160a01b03166370a0823160448301602060405180830381865afa158015612522573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612546919061400d565b90526040805160208101909152600c548152909150600090612569908390612c1a565b336000908152600160209081526040808320815192830190915260038101548252929350612596916127a6565b15612674576040805160208082018352600c5482528251908101909252825482526000916125c391612c1a565b60408051602081019091526003840154815290915060006125e683835190511090565b6125ff5760405180602001604052806000815250612609565b6126098284612bf0565b905061261585826127bd565b336000818152600160208190526040808320838155918201839055600282018390556003820183905560049091018290555192975090917fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc2829190a25050505b604080516020810190915260035481526000906126919084612b96565b604080516020810190915260035481529091506126ae9082612bf0565b516003556040805160208101909152600254815290945084906126d19085612bf0565b516002558351855160405133907f9d349c102bec959fb7f20f9a3621e015819d3ae4ed6e9afd1f56a69d5845600690600090a48451600554612720916001600160a01b03909116903390612de2565b835160045461273e916001600160a01b039091169033903090612a41565b600480548551604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b15801561278257600080fd5b505af1158015612796573d6000803e3d6000fd5b5050505050505050610e8c612ab2565b60006127b182612bbb565b51835111905092915050565b60408051602081019091526000815260408051602081019091528251845182916127e79190612807565b90529392505050565b60006127fb82612bbb565b51835110905092915050565b6000610696828461403c565b6000610696828461404f565b60005460ff166107df5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610854565b604080516020810190915260008152600f546001600160a01b03163b612898575081610699565b600f5460405162ff49b960e41b815284516004820152602481018490526001600160a01b0390911690630ff49b9090604401602060405180830381865afa925050508015612903575060408051601f3d908101601f191682019092526129009181019061406e565b60015b61290e575081610699565b9050610699565b60095442106107df5760405162461bcd60e51b815260206004820152601860248201527f4f6e6c792063616c6c61626c65207072652d65787069727900000000000000006044820152606401610854565b61296f816129c1565b60010154156123505760405162461bcd60e51b815260206004820152601260248201527114195b991a5b99c81dda5d1a191c985dd85b60721b6044820152606401610854565b6000805460ff19169055565b6000816129cd81613751565b50506001600160a01b0316600090815260016020526040902090565b604080516020810190915260008152604080516020810190915260038401548152612a1490836127bd565b51600380850191909155604080516020810190915290548152612a3790836127bd565b5160035550919050565b6040516001600160a01b0380851660248301528316604482015260648101829052612aac9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526137cf565b50505050565b6000805460ff19166001179055565b604080516020810190915260008152600f546001600160a01b03163b612af65750506040805160208101909152601354815290565b600f54604051632a31263760e01b81528351600482015260135460248201526001600160a01b0390911690632a31263790604401602060405180830381865afa925050508015612b63575060408051601f3d908101601f19168201909252612b609181019061406e565b60015b6106995750506040805160208101909152601354815290565b612b866000612bbb565b5160028201556000600190910155565b6040805160208101909152600081528151835110612bb45781610696565b5090919050565b604080516020810190915260008152604080516020810190915280612be884670de0b6b3a7640000612813565b905292915050565b60408051602081019091526000815260408051602081019091528251845182916127e791906138a4565b6040805160208101909152600081526040805160208101909152825184518291670de0b6b3a764000091612c4d91612813565b6127e791906140be565b60408051602081019091526000815260408051602081019091528251845182916127e791612c8d90670de0b6b3a7640000612813565b906138b0565b6000612c9e856129c1565b60408051602081019091528154908190528551919250148015612cd4575060408051602081019091526003820154908190528351145b15612ce957612ce2856132d2565b5050612aac565b612cf38184612d94565b50604080516020810190915281548152600090612d109086612bf0565b6040805160208101909152600b549081905281519192501115612d455760405162461bcd60e51b815260040161085490613f80565b80518255604080516020810190915260028301548152612d659084612bf0565b51600280840191909155604080516020810190915290548152612d889086612bf0565b51600255505050505050565b604080516020810190915260008152604080516020810190915260038401548152612dbf9083612bf0565b51600380850191909155604080516020810190915290548152612a379083612bf0565b6040516001600160a01b03831660248201526044810182905261074a90849063a9059cbb60e01b90606401612a75565b60008054610100900460ff166002811115612e2f57612e2f613d50565b146107df5760405162461bcd60e51b815260206004820152601a60248201527f436f6e7472616374207374617465206973206e6f74204f50454e0000000000006044820152606401610854565b6000612e866138bc565b600d54600554919250612ea6916001600160a01b03169033903090612a41565b600d54600554612ec3916001600160a01b03909116908390613941565b806001600160a01b03166311df92f1612edb846133d4565b600554600d546040516001600160e01b031960e086901b168152612f13939288926008926001600160a01b0390921691600401614184565b6020604051808303816000875af1158015612f32573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a919061400d565b6000612f628284613005565b600181810154919250600160a01b90910460ff1690816004811115612f8957612f89613d50565b1180612fb9575042612f9a836139ee565b11158015612fb957506001816004811115612fb757612fb7613d50565b145b612aac5760405162461bcd60e51b815260206004820152601c60248201527f4c69717569646174696f6e206e6f7420776974686472617761626c65000000006044820152606401610854565b6001600160a01b038216600090815260106020526040812080548310801561306f5750600081848154811061303c5761303c613f47565b906000526020600020906008020160010160149054906101000a900460ff16600481111561306c5761306c613d50565b14155b6130b45760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a59081b1a5c5d5a59185d1a5bdb88125160521b6044820152606401610854565b8083815481106130c6576130c6613f47565b906000526020600020906008020191505092915050565b60006130e98284613005565b905060026001820154600160a01b900460ff16600481111561310d5761310d613d50565b1461311757505050565b613124816002015461360c565b5160078201819055604080516020808201835292815281519283019091526003830154825260009161315591612c1a565b6040805160208101909152600784015481529091506000906131819061317a90612ac1565b8390612c1a565b604080516020810190915260058501549081905281519192501015806131a85760046131ab565b60035b60018501805460ff60a01b1916600160a01b8360048111156131cf576131cf613d50565b021790555060018401546006850154604080516001600160a01b039283168152602081018a9052841515818301529051928216929188169133917f6c5582199868fabbe697f9ea10abe481bacf53ac78c02a965b34dff82fd20e3b919081900360600190a4505050505050565b6040805160208101909152600081526040805160208101909152600384015481526132679083612bf0565b5160038085019190915560408051602081019091529054815261328a9083612bf0565b5160035561329783613a09565b61159b5760405162461bcd60e51b815260206004820152600c60248201526b21a9103132b637bb9023a1a960a11b6044820152606401610854565b60408051602081019091526000815260006132ec836129c1565b6040805160208082018352600380548084528451808401865291860154825284519283019094529281529293509161332391612bf0565b516003556040805160208082018352845482528251908101909252600254825261334d9190612bf0565b5160029081556001600160a01b038516600081815260016020819052604080832083815591820183905593810182905560038101829055600401819055915190917fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc28291a2604080516020810190915260035481526133cc908290612bf0565b949350505050565b600f546000906001600160a01b03163b6133f057505060075490565b600f5460075460405163f19371b760e01b81526001600160a01b039092169163f19371b79161342c918690600401918252602082015260400190565b602060405180830381865afa925050508015613465575060408051601f3d908101601f191682019092526134629181019061400d565b60015b61069957505060075490565b6040805160208082018352600354825282519081019092526002548252600091829161349c91613a34565b905060006134aa8585613a34565b90506134b882825190511190565b1595945050505050565b60006134cd82612bbb565b51835114905092915050565b6009544210156107df5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c792063616c6c61626c6520706f73742d657870697279000000000000006044820152606401610854565b60006135378284613005565b9050613542816139ee565b4210801561356e5750600180820154600160a01b900460ff16600481111561356c5761356c613d50565b145b61074a5760405162461bcd60e51b815260206004820152601a60248201527f4c69717569646174696f6e206e6f742064697370757461626c650000000000006044820152606401610854565b600e80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60408051602081019091526000815260006136256138bc565b9050806001600160a01b031663bc58ccaa30613640866133d4565b8660086040518563ffffffff1660e01b815260040161366294939291906141c0565b602060405180830381865afa15801561367f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a39190613feb565b6136ac57600080fd5b6000816001600160a01b03166353b592396136c6866133d4565b8660086040518463ffffffff1660e01b81526004016136e7939291906141f7565b6020604051808303816000875af1158015613706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061372a919061400d565b90506000811215613739575060005b6133cc60405180602001604052808381525085612871565b6001600160a01b03811660009081526001602090815260408083208151928301909152600301548152613783916127a6565b6123505760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e20686173206e6f20636f6c6c61746572616c0000000000006044820152606401610854565b6000613824826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a669092919063ffffffff16565b90508051600014806138455750808060200190518101906138459190613feb565b61074a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610854565b6000610696828461421f565b600061069682846140be565b6006546040516302abf57960e61b81526f4f7074696d69737469634f7261636c6560801b60048201526000916001600160a01b03169063aafd5e4090602401602060405180830381865afa158015613918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393c9190614232565b905090565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015613991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b5919061400d565b9050612aac8463095ea7b360e01b856139ce868661403c565b6040516001600160a01b0390921660248301526044820152606401612a75565b6000610699601254836002015461280790919063ffffffff16565b6040805160208082018352600384015482528251908101909252825482526000916106999190613471565b604080516020810190915260008152613a4e8260006127a6565b613a5c5761290e6000612bbb565b61290e8383612c57565b60606133cc848460008585600080866001600160a01b03168587604051613a8d919061424f565b60006040518083038185875af1925050503d8060008114613aca576040519150601f19603f3d011682016040523d82523d6000602084013e613acf565b606091505b5091509150613ae087838387613aeb565b979650505050505050565b60608315613b5a578251600003613b53576001600160a01b0385163b613b535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610854565b50816133cc565b6133cc8383815115613b6f5781518083602001fd5b8060405162461bcd60e51b81526004016108549190613e43565b600060208284031215613b9b57600080fd5b6040516020810181811067ffffffffffffffff82111715613bcc57634e487b7160e01b600052604160045260246000fd5b6040529135825250919050565b60008060408385031215613bec57600080fd5b613bf68484613b89565b946020939093013593505050565b6001600160a01b038116811461235057600080fd5b60008060408385031215613c2c57600080fd5b8235613c3781613c04565b9150613c468460208501613b89565b90509250929050565b600060208284031215613c6157600080fd5b6106968383613b89565b60006020828403121561159b57600080fd5b600080600080600060a08688031215613c9557600080fd5b8535613ca081613c04565b9450613caf8760208801613c6b565b9350613cbe8760408801613c6b565b9250613ccd8760608801613c6b565b949793965091946080013592915050565b60008060408385031215613cf157600080fd5b823591506020830135613d0381613c04565b809150509250929050565b600060208284031215613d2057600080fd5b8135613d2b81613c04565b9392505050565b60008060408385031215613d4557600080fd5b8235613bf681613c04565b634e487b7160e01b600052602160045260246000fd5b60058110613d7657613d76613d50565b9052565b6001600160a01b038a811682528981166020830152610120820190613da2604084018b613d66565b606083019890985295516080820152935160a0850152915160c084015290931660e08201529151610100909201919091529392505050565b600060208284031215613dec57600080fd5b5035919050565b60005b83811015613e0e578181015183820152602001613df6565b50506000910152565b60008151808452613e2f816020860160208601613df3565b601f01601f19169290920160200192915050565b6020815260006106966020830184613e17565b60008060408385031215613e6957600080fd5b613c378484613b89565b6020810160038310613e8757613e87613d50565b91905290565b602080825282518282018190526000919060409081850190868401855b82811015613f3a57815180516001600160a01b03908116865287820151168786015285810151613edc87870182613d66565b5060608181015190860152608080820151519086015260a080820151519086015260c080820151519086015260e0808201516001600160a01b0316908601526101009081015151908501526101209093019290850190600101613eaa565b5091979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613f6f57600080fd5b815160ff81168114613d2b57600080fd5b6020808252601e908201527f42656c6f77206d696e696d756d2073706f6e736f7220706f736974696f6e0000604082015260600190565b600181811c90821680613fcb57607f821691505b60208210810361159b57634e487b7160e01b600052602260045260246000fd5b600060208284031215613ffd57600080fd5b81518015158114613d2b57600080fd5b60006020828403121561401f57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069957610699614026565b600081600019048311821515161561406957614069614026565b500290565b60006020828403121561408057600080fd5b6040516020810181811067ffffffffffffffff821117156140b157634e487b7160e01b600052604160045260246000fd5b6040529151825250919050565b6000826140db57634e487b7160e01b600052601260045260246000fd5b500490565b8054600090600181811c90808316806140fa57607f831692505b6020808410820361411b57634e487b7160e01b600052602260045260246000fd5b83885260208801828015614136576001811461414c57614177565b60ff198716825285151560051b82019750614177565b60008981526020902060005b8781101561417157815484820152908601908401614158565b83019850505b5050505050505092915050565b85815284602082015260a0604082015260006141a360a08301866140e0565b6001600160a01b0394909416606083015250608001529392505050565b60018060a01b03851681528360208201528260408201526080606082015260006141ed60808301846140e0565b9695505050505050565b83815282602082015260606040820152600061421660608301846140e0565b95945050505050565b8181038181111561069957610699614026565b60006020828403121561424457600080fd5b8151613d2b81613c04565b60008251614261818460208701613df3565b919091019291505056fea2646970667358221220311014b7faed1c8dc787c28fef8c8cf8e75316166b5232520f57b52729711bfc64736f6c6343000810003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000065660070000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000467d3b8d17e412194429044def3a27a06a8a51a00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c300000000000000000000000000000000000000000000000000000000000000004e554d45524943414c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000000002a30000000000000000000000000000000000000000000000000010a741a462780000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000853a0d2313c0000000000000000000000000000f05c8984a9f9cc5d3981d852331895220d09cdc8000000000000000000000000000000000000000000000000000000000000020573796e746849443a20225654222c20713a225369676e7570206f6e2068747470733a2f2f7477656c7665646174612e636f6d2f20616e64206765742061206672656520415049206b65792e20517565727920746869732075726c2068747470733a2f2f6170692e7477656c7665646174612e636f6d2f74696d655f7365726965733f6170696b65793d4150495f4b455926696e74657276616c3d31356d696e2674696d657a6f6e653d555443266f726465723d4153432673796d626f6c3d56542673746172745f646174653d53544152545f4441544526656e645f646174653d454e445f444154453b5265706c61636520746865204150495f4b4559207769746820796f757220617069206b65792e205265706c6163652074686520454e445f4441544520776974682074686520646174652066726f6d2074686520726571756573742074696d657374616d7020696e20595959592d4d4d2d44442048483a6d6d3a737320666f726d617420616e64207265706c616365207468652053544152545f4441544520617320454e445f44415445206d696e7573203420646179732e2050726f706f73652074686520707269636520776869636820697320746865206c6173742074726164656420636c6f73696e672070726963652066726f6d207468652076616c756573206c69737420696e2074686520726573706f6e7365206a736f6e2e22000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102955760003560e01c806362b5f7f5116101675780639ff4dea8116100ce578063d1e92c1111610087578063d1e92c1114610629578063e3c0f9cb1461063c578063edfa9a9b14610646578063f0391daf14610650578063f2fde38b1461065a578063fcccedc71461066d57600080fd5b80639ff4dea8146105bf578063a1c4d1e7146105c8578063a765fbea146105e8578063b795f0d4146105fb578063b9a3c84c14610603578063bc1216301461061657600080fd5b806385209ee01161012057806385209ee01461055e5780638da5cb5b1461057d57806392120aec146105905780639375f0e91461059a57806397523661146105ad5780639f43ddd2146105b657600080fd5b806362b5f7f5146104fe57806365599057146105115780636ba2f992146105265780637048594b1461053957806379599f961461054c5780637e398c221461055457600080fd5b80633403c2fc1161020b5780634ead6e51116101c45780634ead6e51146103ef5780634f8c48471461041457806355f575101461043c5780635617151c146104c55780635aa266c9146104d85780635f1af1ca146104eb57600080fd5b80633403c2fc14610380578063360598e11461038857806336980f58146103c05780633ee7a5ce146103c857806343e4771b146103db57806348e30c3f146103e557600080fd5b8063197f78481161025d578063197f784814610323578063226112801461033657806325ed4dd81461033e5780632d5436cf146103655780632e154f2e1461036e57806333a46ca21461037857600080fd5b8063081b314e1461029a5780630c9229ca146102b75780630de15fd9146102c15780630ff49b90146102ec57806318928a0c1461030e575b600080fd5b6015546102a49081565b6040519081526020015b60405180910390f35b6002546102a49081565b6005546102d4906001600160a01b031681565b6040516001600160a01b0390911681526020016102ae565b6102ff6102fa366004613bd9565b610675565b604051905181526020016102ae565b61032161031c366004613c19565b61069f565b005b6102ff610331366004613c4f565b61074f565b61032161076f565b61035161034c366004613c7d565b6107e1565b6040805192835290516020830152016102ae565b6102a460125481565b6014546102a49081565b6102ff610d6a565b610321610e8f565b61039b610396366004613cde565b610f5c565b60408051825151815260208084015151908201529181015151908201526060016102ae565b610321611450565b6102ff6103d6366004613c4f565b6114e9565b6003546102a49081565b6013546102a49081565b6104026103fd366004613d0e565b6115a1565b60405160ff90911681526020016102ae565b610427610422366004613d32565b611609565b6040516102ae99989796959493929190613d7a565b61049861044a366004613d0e565b60016020818152600092835260409283902083518083018552815481529281015484518084018652600283015481528551938401909552600382015483526004909101549293909290919085565b6040805195518652602086019490945291519284019290925290516060830152608082015260a0016102ae565b6103216104d3366004613d0e565b6116ae565b6103216104e6366004613c4f565b61184c565b6102ff6104f9366004613c4f565b6119ad565b6102a461050c366004613dda565b611bbf565b610519611bd2565b6040516102ae9190613e43565b610321610534366004613e56565b611c60565b6004546102d4906001600160a01b031681565b610321611f00565b6016546102a49081565b60005461057090610100900460ff1681565b6040516102ae9190613e73565b600e546102d4906001600160a01b031681565b600b546102a49081565b600f546102d4906001600160a01b031681565b6102a460075481565b6102a460095481565b6102a4600a5481565b6105db6105d6366004613d0e565b611f6e565b6040516102ae9190613e8d565b6102ff6105f6366004613cde565b6120b1565b610321612206565b6006546102d4906001600160a01b031681565b610321610624366004613c4f565b612277565b610321610637366004613c4f565b612346565b6011546102a49081565b600c546102a49081565b600d546102a49081565b610321610668366004613d0e565b612353565b6102ff612406565b60408051602081019091526000815261068c61281f565b6106968383612871565b90505b92915050565b6106a7612915565b816106b181612966565b6106b961281f565b6106c16129b5565b6106cc8260006127a6565b6106d557600080fd5b60006106e0846129c1565b90506106ec81846129e9565b5082516040516001600160a01b038616907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90600090a38251600554610741916001600160a01b039091169033903090612a41565b5061074a612ab2565b505050565b60408051602081019091526000815261076661281f565b61069982612ac1565b61077761281f565b61077f6129b5565b600061078a336129c1565b9050806001015460000361079d57600080fd5b600281015460405133907f74d8a3658feb89d1a5c335229bbbfc3bbcfaf492769feb7aa4cd2d92efeaf69190600090a36107d681612b7c565b506107df612ab2565b565b60006107f96040518060200160405280600081525090565b610801612915565b61080961281f565b6108116129b5565b8242111561085d5760405162461bcd60e51b81526020600482015260146024820152734d696e656420616674657220646561646c696e6560601b60448201526064015b60405180910390fd5b6000610868886129c1565b905061089061087c36879003870187613c4f565b604080516020810190915283548152612b96565b915061089d8260006127a6565b6108a657600080fd5b60408051602081019091526003820154815260006108c381612bbb565b6040805160208101909152600285015490819052835191925011610901576040805160208101909152600284015481526108fe908390612bf0565b90505b6040805160208101909152835481526109368261092d83610927368e90038e018e613c4f565b90612c1a565b90519051101590565b6109825760405162461bcd60e51b815260206004820152601e60248201527f4352206973206d6f7265207468616e206d6178206c69712e20707269636500006044820152606401610854565b6109a28261099983610927368f90038f018f613c4f565b90519051111590565b6109ee5760405162461bcd60e51b815260206004820152601e60248201527f4352206973206c657373207468616e206d696e206c69712e20707269636500006044820152606401610854565b50604080516020810190915260008152604080516020810190915260008152604080516020810190915285548152600090610a2a908890612c57565b9050610a368582612c1a565b9250610a428482612c1a565b604080516020810190915260028801548152909250600090610a649083612c1a565b9050610a728e898684612c93565b50506040805160208082018352600d54825282519081019092526011548252610aa591610a9f90856127bd565b906127bd565b516011556001600160a01b038c1660008181526010602090815260409182902080548351610120810185529485523392850192909252909950919081016001815260200142815260200188815260200184815260200183815260200160006001600160a01b03168152602001610b1b6000612bbb565b90528154600181810184556000938452602093849020835160089093020180546001600160a01b039384166001600160a01b0319918216178255948401519181018054929093169482168517835560408401519394909392916001600160a81b03191617600160a01b836004811115610b9657610b96613d50565b021790555060608201516002820155608082015151600382015560a082015151600482015560c082015151600582015560e08201516006820180546001600160a01b0319166001600160a01b0390921691909117905561010090910151516007909101556040805160208101909152600b548152600186015415801590610c205750428660010154115b8015610c2e57508051875110155b15610c4757600a54610c41904290612807565b60018701555b87336001600160a01b03168e6001600160a01b03167f39b4371645b4132767fd76a1aad3108ff95c20d7b687b24d171555f5459a75978a600001518760000151876000015142604051610cb3949392919093845260208401929092526040830152606082015260800190565b60405180910390a48651600454610cd9916001600160a01b039091169033903090612a41565b600480548851604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b158015610d1d57600080fd5b505af1158015610d31573d6000803e3d6000fd5b5050600d54600554610d5293506001600160a01b0316915033903090612a41565b505050505050610d60612ab2565b9550959350505050565b604080516020810190915260008152610d81612915565b610d8961281f565b610d916129b5565b6000610d9c336129c1565b90508060010154600014158015610db7575042816001015411155b610dc057600080fd5b60408051602080820183526000825282518082018452600385015481528351918201909352600284015490819052915190911115610e105750604080516020810190915260038201548152610e24565b506040805160208101909152600282015481525b610e2e8282612d94565b9250610e3982612b7c565b8251600554610e55916001600160a01b03909116903390612de2565b825160405133907fc86c3298cb79f486674dca87d9247e88b76146160e7d412cc59b26b14c358a6890600090a35050610e8c612ab2565b90565b610e97612915565b610e9f612e12565b600e546001600160a01b03163314610ef35760405162461bcd60e51b815260206004820152601760248201527631b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606401610854565b6000805461ff00191661010017905560098054429182905590610f1590612e7c565b60095460405133917fd39eeb7157d9c446579a0893ecf9ecd87d1f466cdb270c6a189cf38ca1e30f4891610f5191858252602082015260400190565b60405180910390a250565b610f996040805160808101825260006060820181815282528251602080820185528282528084019190915283519081018452908152909182015290565b8282610fa58282612f56565b610fad61281f565b610fb56129b5565b6000610fc18587613005565b9050610fcd86866130dd565b604080516020808201835260078401548252825190810190925260038301548252600091610ffa91612c1a565b6040805160208101909152601654815290915060009061101a9083612c1a565b6040805160208101909152601554815290915060009061103a9084612c1a565b604080516020808201835260145482528251908101909252600487015482529192506000916110699190612c1a565b90506110a86040805160808101825260006060820181815282528251602080820185528282528084019190915283519081018452908152909182015290565b60036001870154600160a01b900460ff1660048111156110ca576110ca613d50565b03611201576040805160208101909152600d5481526110ed90610a9f86856127bd565b60408083019190915280516020810190915260048701548152611116908490610a9f9088612bf0565b815261112c846111268786612bf0565b90612bf0565b6020808301829052604080519182019052601154815261114b91612bf0565b5160118190558151604080516020810190915291825261116b9190612bf0565b51601181905560408083015181516020810190925291815261118c91612bf0565b5160115560068601546040820151516005546111b6926001600160a01b0391821692911690612de2565b60018601546020820151516005546111dc926001600160a01b0391821692911690612de2565b85548151516005546111fc926001600160a01b0391821692911690612de2565b611336565b60046001870154600160a01b900460ff16600481111561122357611223613d50565b0361129e576040805160208082018352600d54825282519081019092526004880154825261125591610a9f90856127bd565b6020808301829052604080519182019052601154815261127491612bf0565b5160115560018601546020820151516005546111fc926001600160a01b0391821692911690612de2565b600180870154600160a01b900460ff1660048111156112bf576112bf613d50565b03611336576040805160208082018352600d5482528251908101909252600488015482526112ed91906127bd565b6020808301829052604080519182019052601154815261130c91612bf0565b516011556001860154602082015151600554611336926001600160a01b0391821692911690612de2565b6001860154600160a01b900460ff16600481111561135657611356613d50565b602082810151516040808501515185515160078c015483519485529484019190915290820152606081019190915233907fb479588a37dc7f6bac1c91587fcfc539cac4949cf26bb536ad9c8d061f00f50d9060800160405180910390a36001600160a01b038a16600090815260106020526040902080548c9081106113dd576113dd613f47565b60009182526020822060089091020180546001600160a01b031990811682556001820180546001600160a81b03191690556002820183905560038201839055600482018390556005820183905560068201805490911690556007015597505050505050611448612ab2565b505092915050565b611458612915565b61146061281f565b6114686129b5565b6000611473336129c1565b9050806004015460001461148657600080fd5b600061149d600a544261280790919063ffffffff16565b905060095481106114ad57600080fd5b6004820181905560405133907fbf457c80c8bf299d5c48272c4c1168bf87b33d83b13f0ab9aac332ce1161ed1e90600090a250506107df612ab2565b604080516020810190915260008152611500612915565b3361150a81612966565b61151261281f565b61151a6129b5565b6115258360006127a6565b61152e57600080fd5b6000611539336129c1565b9050611545818561323c565b80516040519194509033907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b6590600090a38251600554611592916001600160a01b03909116903390612de2565b5061159b612ab2565b50919050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156115fd575060408051601f3d908101601f191682019092526115fa91810190613f5d565b60015b61069957506012919050565b6010602052816000526040600020818154811061162557600080fd5b600091825260209182902060089190910201805460018201546002830154604080518087018252600386015481528151808801835260048701548152825180890184526005880154815260068801548451998a0190945260079097015488526001600160a01b0395861699508585169850600160a01b90940460ff169692959094909291169089565b6116b6612915565b336116c081612966565b6116c861281f565b6116d06129b5565b6117116116dd6000612bbb565b6001600160a01b03841660009081526001602090815260409182902082519182019092526003909101548152905190511490565b61171a57600080fd5b6000611725336129c1565b90508060040154600014158015611740575042816004015411155b61174957600080fd5b600060048083018281556001600160a01b038616808452600160208190526040808620875481558288015481840155600280890154818301556003808a0154818401559554918701919091553380885282882088815593840188905590830187905593820186905593018490559151919290917ff1a2dcf23621f1a96185c79d39a5776b5ba3dadbea70c5aa86d84c17c7e9418e9190a36040516001600160a01b038416907ff60993fa76f94c9e0a803526ee6e1314814ed4d2b0d223febf1436b36897fb3790600090a260405133907fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc28290600090a250611848612ab2565b5050565b611854612915565b3361185e81612966565b61186661281f565b61186e6129b5565b6000611879336129c1565b60408051602081019091528154908190528451919250101561189a57600080fd5b6040805160208101909152815481526000906118b69085612bf0565b6040805160208101909152600b5490819052815191925011156118d857600080fd5b80518255604080516020810190915260025481526118f69085612bf0565b516002558051845160405133907f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d090600090a48351600454611947916001600160a01b039091169033903090612a41565b600480548551604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b15801561198b57600080fd5b505af115801561199f573d6000803e3d6000fd5b505050505050611848612ab2565b604080516020810190915260008152336119c681612966565b6119ce61281f565b6119d66129b5565b60006119e1336129c1565b604080516020810190915281549081905285519192501015611a0257600080fd5b604080516020810190915281548152600090611a1f908690612c57565b604080516020810190915260038401548152909150600090611a42908390612c1a565b6040805160208101909152845490819052875191925003611a6d57611a66336132d2565b9450611aef565b611a778382612d94565b604080516020810190915284548152909550600090611a969088612bf0565b6040805160208101909152600b549081905281519192501115611acb5760405162461bcd60e51b815260040161085490613f80565b8051845560408051602081019091526002548152611ae99088612bf0565b51600255505b8551855160405133907fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92990600090a48451600554611b3a916001600160a01b03909116903390612de2565b8551600454611b58916001600160a01b039091169033903090612a41565b600480548751604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b158015611b9c57600080fd5b505af1158015611bb0573d6000803e3d6000fd5b5050505050505061159b612ab2565b6000611bc961281f565b610699826133d4565b60088054611bdf90613fb7565b80601f0160208091040260200160405190810160405280929190818152602001828054611c0b90613fb7565b8015611c585780601f10611c2d57610100808354040283529160200191611c58565b820191906000526020600020905b815481529060010190602001808311611c3b57829003601f168201915b505050505081565b611c68612915565b611c7061281f565b611c786129b5565b33600090815260016020908152604091829020825191820190925260038201548152611cc690611ca890856127bd565b604080516020810190915283548152611cc190856127bd565b613471565b80611cd65750611cd68383613471565b611d225760405162461bcd60e51b815260206004820152601760248201527f496e73756666696369656e7420636f6c6c61746572616c0000000000000000006044820152606401610854565b600181015415611d695760405162461bcd60e51b815260206004820152601260248201527114195b991a5b99c81dda5d1a191c985dd85b60721b6044820152606401610854565b604080516020810190915281548152611d839060006134c2565b15611de6576040805160208101909152600b549081905282511015611dba5760405162461bcd60e51b815260040161085490613f80565b60405133907ff60993fa76f94c9e0a803526ee6e1314814ed4d2b0d223febf1436b36897fb3790600090a25b611df081846129e9565b50604080516020810190915281548152611e0a90836127bd565b51815560408051602081019091526002548152611e2790836127bd565b516002558151835160405133907f4b82aa16e071a61de1a6b9aeec9edab0356331f8122c78683b469ac8e685dabc90600090a48251600554611e78916001600160a01b039091169033903090612a41565b6004805483516040516340c10f1960e01b8152339381019390935260248301526001600160a01b0316906340c10f19906044016020604051808303816000875af1158015611eca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eee9190613feb565b611ef757600080fd5b50611848612ab2565b611f086134d9565b611f10612e12565b611f1861281f565b611f206129b5565b6000805461ff001916610100179055600954611f3b90612e7c565b60405133907f18600820405d6cf356e3556301762ca32395e72d8c81494fa344835c9da3633d90600090a26107df612ab2565b6060611f7861281f565b6001600160a01b038216600090815260106020908152604080832080548251818502810185019093528083529193909284015b828210156120a657600084815260209081902060408051610120810182526008860290920180546001600160a01b039081168452600182015490811694840194909452919290830190600160a01b900460ff16600481111561200f5761200f613d50565b600481111561202057612020613d50565b815260028201546020808301919091526040805180830182526003850154815281840152805180830182526004850154815260608401528051808301825260058501548152608084015260068401546001600160a01b031660a08401528051808301909152600790930154835260c0909101919091529082526001929092019101611fab565b505050509050919050565b60408051602081019091526000815282826120cc828261352b565b6120d461281f565b6120dc6129b5565b60006120e88587613005565b604080516020808201835260145482528251908101909252600483015482529192506000916121179190612c1a565b6040805160208101909152601154815290915061213490826127bd565b5160115560018201805460ff60a01b1916600160a11b1790556006820180546001600160a01b03191633179055600282015461216f90612e7c565b60018201548151604080518a8152602081019290925233926001600160a01b0390811692908a16917fcaca181ccad7979cf36ed4fc921e496001ab5264608f0fac7007ae1b43d36102910160405180910390a46040805160208101909152600d5481526121dd9082906127bd565b81516005549196506121fc916001600160a01b03169033903090612a41565b5050611448612ab2565b61220e612915565b61221661281f565b61221e6129b5565b6000612229336129c1565b9050806004015460000361223c57600080fd5b60405133907f2e5702420c76e041698ad7ba57a9ff5cadccf647ea8d96e6007a40b5b2662f5690600090a260006004909101556107df612ab2565b61227f612915565b3361228981612966565b61229161281f565b6122996129b5565b60006122a4336129c1565b90506122b18360006127a6565b80156122d157506040805160208101909152600382015490819052835111155b6122da57600080fd5b60006122f1600a544261280790919063ffffffff16565b9050600954811061230157600080fd5b6001820181905583516002830181905560405133907fd33b726e11d2c5d38e6702b16613df0160a07f7ba5185455ee3c45d0494fab1190600090a35050611848612ab2565b612350338261069f565b50565b600e546001600160a01b031633146123a75760405162461bcd60e51b815260206004820152601760248201527631b0b63632b91034b9903737ba103a34329037bbb732b960491b6044820152606401610854565b6001600160a01b0381166123fd5760405162461bcd60e51b815260206004820152601d60248201527f6e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401610854565b612350816135ba565b60408051602081019091526000815261241d6134d9565b61242561281f565b61242d6129b5565b60008054610100900460ff16600281111561244a5761244a613d50565b0361248c5760405162461bcd60e51b81526020600482015260126024820152712ab732bc3834b932b2103837b9b4ba34b7b760711b6044820152606401610854565b6002600054610100900460ff1660028111156124aa576124aa613d50565b146124ce576124ba60095461360c565b51600c556000805461ff0019166102001790555b6040805160208101918290526004546370a0823160e01b90925233602482015260009181906001600160a01b03166370a0823160448301602060405180830381865afa158015612522573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612546919061400d565b90526040805160208101909152600c548152909150600090612569908390612c1a565b336000908152600160209081526040808320815192830190915260038101548252929350612596916127a6565b15612674576040805160208082018352600c5482528251908101909252825482526000916125c391612c1a565b60408051602081019091526003840154815290915060006125e683835190511090565b6125ff5760405180602001604052806000815250612609565b6126098284612bf0565b905061261585826127bd565b336000818152600160208190526040808320838155918201839055600282018390556003820183905560049091018290555192975090917fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc2829190a25050505b604080516020810190915260035481526000906126919084612b96565b604080516020810190915260035481529091506126ae9082612bf0565b516003556040805160208101909152600254815290945084906126d19085612bf0565b516002558351855160405133907f9d349c102bec959fb7f20f9a3621e015819d3ae4ed6e9afd1f56a69d5845600690600090a48451600554612720916001600160a01b03909116903390612de2565b835160045461273e916001600160a01b039091169033903090612a41565b600480548551604051630852cd8d60e31b8152928301526001600160a01b0316906342966c6890602401600060405180830381600087803b15801561278257600080fd5b505af1158015612796573d6000803e3d6000fd5b5050505050505050610e8c612ab2565b60006127b182612bbb565b51835111905092915050565b60408051602081019091526000815260408051602081019091528251845182916127e79190612807565b90529392505050565b60006127fb82612bbb565b51835110905092915050565b6000610696828461403c565b6000610696828461404f565b60005460ff166107df5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610854565b604080516020810190915260008152600f546001600160a01b03163b612898575081610699565b600f5460405162ff49b960e41b815284516004820152602481018490526001600160a01b0390911690630ff49b9090604401602060405180830381865afa925050508015612903575060408051601f3d908101601f191682019092526129009181019061406e565b60015b61290e575081610699565b9050610699565b60095442106107df5760405162461bcd60e51b815260206004820152601860248201527f4f6e6c792063616c6c61626c65207072652d65787069727900000000000000006044820152606401610854565b61296f816129c1565b60010154156123505760405162461bcd60e51b815260206004820152601260248201527114195b991a5b99c81dda5d1a191c985dd85b60721b6044820152606401610854565b6000805460ff19169055565b6000816129cd81613751565b50506001600160a01b0316600090815260016020526040902090565b604080516020810190915260008152604080516020810190915260038401548152612a1490836127bd565b51600380850191909155604080516020810190915290548152612a3790836127bd565b5160035550919050565b6040516001600160a01b0380851660248301528316604482015260648101829052612aac9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526137cf565b50505050565b6000805460ff19166001179055565b604080516020810190915260008152600f546001600160a01b03163b612af65750506040805160208101909152601354815290565b600f54604051632a31263760e01b81528351600482015260135460248201526001600160a01b0390911690632a31263790604401602060405180830381865afa925050508015612b63575060408051601f3d908101601f19168201909252612b609181019061406e565b60015b6106995750506040805160208101909152601354815290565b612b866000612bbb565b5160028201556000600190910155565b6040805160208101909152600081528151835110612bb45781610696565b5090919050565b604080516020810190915260008152604080516020810190915280612be884670de0b6b3a7640000612813565b905292915050565b60408051602081019091526000815260408051602081019091528251845182916127e791906138a4565b6040805160208101909152600081526040805160208101909152825184518291670de0b6b3a764000091612c4d91612813565b6127e791906140be565b60408051602081019091526000815260408051602081019091528251845182916127e791612c8d90670de0b6b3a7640000612813565b906138b0565b6000612c9e856129c1565b60408051602081019091528154908190528551919250148015612cd4575060408051602081019091526003820154908190528351145b15612ce957612ce2856132d2565b5050612aac565b612cf38184612d94565b50604080516020810190915281548152600090612d109086612bf0565b6040805160208101909152600b549081905281519192501115612d455760405162461bcd60e51b815260040161085490613f80565b80518255604080516020810190915260028301548152612d659084612bf0565b51600280840191909155604080516020810190915290548152612d889086612bf0565b51600255505050505050565b604080516020810190915260008152604080516020810190915260038401548152612dbf9083612bf0565b51600380850191909155604080516020810190915290548152612a379083612bf0565b6040516001600160a01b03831660248201526044810182905261074a90849063a9059cbb60e01b90606401612a75565b60008054610100900460ff166002811115612e2f57612e2f613d50565b146107df5760405162461bcd60e51b815260206004820152601a60248201527f436f6e7472616374207374617465206973206e6f74204f50454e0000000000006044820152606401610854565b6000612e866138bc565b600d54600554919250612ea6916001600160a01b03169033903090612a41565b600d54600554612ec3916001600160a01b03909116908390613941565b806001600160a01b03166311df92f1612edb846133d4565b600554600d546040516001600160e01b031960e086901b168152612f13939288926008926001600160a01b0390921691600401614184565b6020604051808303816000875af1158015612f32573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a919061400d565b6000612f628284613005565b600181810154919250600160a01b90910460ff1690816004811115612f8957612f89613d50565b1180612fb9575042612f9a836139ee565b11158015612fb957506001816004811115612fb757612fb7613d50565b145b612aac5760405162461bcd60e51b815260206004820152601c60248201527f4c69717569646174696f6e206e6f7420776974686472617761626c65000000006044820152606401610854565b6001600160a01b038216600090815260106020526040812080548310801561306f5750600081848154811061303c5761303c613f47565b906000526020600020906008020160010160149054906101000a900460ff16600481111561306c5761306c613d50565b14155b6130b45760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a59081b1a5c5d5a59185d1a5bdb88125160521b6044820152606401610854565b8083815481106130c6576130c6613f47565b906000526020600020906008020191505092915050565b60006130e98284613005565b905060026001820154600160a01b900460ff16600481111561310d5761310d613d50565b1461311757505050565b613124816002015461360c565b5160078201819055604080516020808201835292815281519283019091526003830154825260009161315591612c1a565b6040805160208101909152600784015481529091506000906131819061317a90612ac1565b8390612c1a565b604080516020810190915260058501549081905281519192501015806131a85760046131ab565b60035b60018501805460ff60a01b1916600160a01b8360048111156131cf576131cf613d50565b021790555060018401546006850154604080516001600160a01b039283168152602081018a9052841515818301529051928216929188169133917f6c5582199868fabbe697f9ea10abe481bacf53ac78c02a965b34dff82fd20e3b919081900360600190a4505050505050565b6040805160208101909152600081526040805160208101909152600384015481526132679083612bf0565b5160038085019190915560408051602081019091529054815261328a9083612bf0565b5160035561329783613a09565b61159b5760405162461bcd60e51b815260206004820152600c60248201526b21a9103132b637bb9023a1a960a11b6044820152606401610854565b60408051602081019091526000815260006132ec836129c1565b6040805160208082018352600380548084528451808401865291860154825284519283019094529281529293509161332391612bf0565b516003556040805160208082018352845482528251908101909252600254825261334d9190612bf0565b5160029081556001600160a01b038516600081815260016020819052604080832083815591820183905593810182905560038101829055600401819055915190917fcad20625296d189a6fc6e5b39d0d544e5bd99dbda0c8f2f0ecffef3e0fbcc28291a2604080516020810190915260035481526133cc908290612bf0565b949350505050565b600f546000906001600160a01b03163b6133f057505060075490565b600f5460075460405163f19371b760e01b81526001600160a01b039092169163f19371b79161342c918690600401918252602082015260400190565b602060405180830381865afa925050508015613465575060408051601f3d908101601f191682019092526134629181019061400d565b60015b61069957505060075490565b6040805160208082018352600354825282519081019092526002548252600091829161349c91613a34565b905060006134aa8585613a34565b90506134b882825190511190565b1595945050505050565b60006134cd82612bbb565b51835114905092915050565b6009544210156107df5760405162461bcd60e51b815260206004820152601960248201527f4f6e6c792063616c6c61626c6520706f73742d657870697279000000000000006044820152606401610854565b60006135378284613005565b9050613542816139ee565b4210801561356e5750600180820154600160a01b900460ff16600481111561356c5761356c613d50565b145b61074a5760405162461bcd60e51b815260206004820152601a60248201527f4c69717569646174696f6e206e6f742064697370757461626c650000000000006044820152606401610854565b600e80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60408051602081019091526000815260006136256138bc565b9050806001600160a01b031663bc58ccaa30613640866133d4565b8660086040518563ffffffff1660e01b815260040161366294939291906141c0565b602060405180830381865afa15801561367f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a39190613feb565b6136ac57600080fd5b6000816001600160a01b03166353b592396136c6866133d4565b8660086040518463ffffffff1660e01b81526004016136e7939291906141f7565b6020604051808303816000875af1158015613706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061372a919061400d565b90506000811215613739575060005b6133cc60405180602001604052808381525085612871565b6001600160a01b03811660009081526001602090815260408083208151928301909152600301548152613783916127a6565b6123505760405162461bcd60e51b815260206004820152601a60248201527f506f736974696f6e20686173206e6f20636f6c6c61746572616c0000000000006044820152606401610854565b6000613824826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613a669092919063ffffffff16565b90508051600014806138455750808060200190518101906138459190613feb565b61074a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610854565b6000610696828461421f565b600061069682846140be565b6006546040516302abf57960e61b81526f4f7074696d69737469634f7261636c6560801b60048201526000916001600160a01b03169063aafd5e4090602401602060405180830381865afa158015613918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393c9190614232565b905090565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015613991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b5919061400d565b9050612aac8463095ea7b360e01b856139ce868661403c565b6040516001600160a01b0390921660248301526044820152606401612a75565b6000610699601254836002015461280790919063ffffffff16565b6040805160208082018352600384015482528251908101909252825482526000916106999190613471565b604080516020810190915260008152613a4e8260006127a6565b613a5c5761290e6000612bbb565b61290e8383612c57565b60606133cc848460008585600080866001600160a01b03168587604051613a8d919061424f565b60006040518083038185875af1925050503d8060008114613aca576040519150601f19603f3d011682016040523d82523d6000602084013e613acf565b606091505b5091509150613ae087838387613aeb565b979650505050505050565b60608315613b5a578251600003613b53576001600160a01b0385163b613b535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610854565b50816133cc565b6133cc8383815115613b6f5781518083602001fd5b8060405162461bcd60e51b81526004016108549190613e43565b600060208284031215613b9b57600080fd5b6040516020810181811067ffffffffffffffff82111715613bcc57634e487b7160e01b600052604160045260246000fd5b6040529135825250919050565b60008060408385031215613bec57600080fd5b613bf68484613b89565b946020939093013593505050565b6001600160a01b038116811461235057600080fd5b60008060408385031215613c2c57600080fd5b8235613c3781613c04565b9150613c468460208501613b89565b90509250929050565b600060208284031215613c6157600080fd5b6106968383613b89565b60006020828403121561159b57600080fd5b600080600080600060a08688031215613c9557600080fd5b8535613ca081613c04565b9450613caf8760208801613c6b565b9350613cbe8760408801613c6b565b9250613ccd8760608801613c6b565b949793965091946080013592915050565b60008060408385031215613cf157600080fd5b823591506020830135613d0381613c04565b809150509250929050565b600060208284031215613d2057600080fd5b8135613d2b81613c04565b9392505050565b60008060408385031215613d4557600080fd5b8235613bf681613c04565b634e487b7160e01b600052602160045260246000fd5b60058110613d7657613d76613d50565b9052565b6001600160a01b038a811682528981166020830152610120820190613da2604084018b613d66565b606083019890985295516080820152935160a0850152915160c084015290931660e08201529151610100909201919091529392505050565b600060208284031215613dec57600080fd5b5035919050565b60005b83811015613e0e578181015183820152602001613df6565b50506000910152565b60008151808452613e2f816020860160208601613df3565b601f01601f19169290920160200192915050565b6020815260006106966020830184613e17565b60008060408385031215613e6957600080fd5b613c378484613b89565b6020810160038310613e8757613e87613d50565b91905290565b602080825282518282018190526000919060409081850190868401855b82811015613f3a57815180516001600160a01b03908116865287820151168786015285810151613edc87870182613d66565b5060608181015190860152608080820151519086015260a080820151519086015260c080820151519086015260e0808201516001600160a01b0316908601526101009081015151908501526101209093019290850190600101613eaa565b5091979650505050505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613f6f57600080fd5b815160ff81168114613d2b57600080fd5b6020808252601e908201527f42656c6f77206d696e696d756d2073706f6e736f7220706f736974696f6e0000604082015260600190565b600181811c90821680613fcb57607f821691505b60208210810361159b57634e487b7160e01b600052602260045260246000fd5b600060208284031215613ffd57600080fd5b81518015158114613d2b57600080fd5b60006020828403121561401f57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561069957610699614026565b600081600019048311821515161561406957614069614026565b500290565b60006020828403121561408057600080fd5b6040516020810181811067ffffffffffffffff821117156140b157634e487b7160e01b600052604160045260246000fd5b6040529151825250919050565b6000826140db57634e487b7160e01b600052601260045260246000fd5b500490565b8054600090600181811c90808316806140fa57607f831692505b6020808410820361411b57634e487b7160e01b600052602260045260246000fd5b83885260208801828015614136576001811461414c57614177565b60ff198716825285151560051b82019750614177565b60008981526020902060005b8781101561417157815484820152908601908401614158565b83019850505b5050505050505092915050565b85815284602082015260a0604082015260006141a360a08301866140e0565b6001600160a01b0394909416606083015250608001529392505050565b60018060a01b03851681528360208201528260408201526080606082015260006141ed60808301846140e0565b9695505050505050565b83815282602082015260606040820152600061421660608301846140e0565b95945050505050565b8181038181111561069957610699614026565b60006020828403121561424457600080fd5b8151613d2b81613c04565b60008251614261818460208701613df3565b919091019291505056fea2646970667358221220311014b7faed1c8dc787c28fef8c8cf8e75316166b5232520f57b52729711bfc64736f6c63430008100033

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

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000065660070000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000467d3b8d17e412194429044def3a27a06a8a51a00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c300000000000000000000000000000000000000000000000000000000000000004e554d45524943414c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000000002a30000000000000000000000000000000000000000000000000010a741a462780000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000853a0d2313c0000000000000000000000000000f05c8984a9f9cc5d3981d852331895220d09cdc8000000000000000000000000000000000000000000000000000000000000020573796e746849443a20225654222c20713a225369676e7570206f6e2068747470733a2f2f7477656c7665646174612e636f6d2f20616e64206765742061206672656520415049206b65792e20517565727920746869732075726c2068747470733a2f2f6170692e7477656c7665646174612e636f6d2f74696d655f7365726965733f6170696b65793d4150495f4b455926696e74657276616c3d31356d696e2674696d657a6f6e653d555443266f726465723d4153432673796d626f6c3d56542673746172745f646174653d53544152545f4441544526656e645f646174653d454e445f444154453b5265706c61636520746865204150495f4b4559207769746820796f757220617069206b65792e205265706c6163652074686520454e445f4441544520776974682074686520646174652066726f6d2074686520726571756573742074696d657374616d7020696e20595959592d4d4d2d44442048483a6d6d3a737320666f726d617420616e64207265706c616365207468652053544152545f4441544520617320454e445f44415445206d696e7573203420646179732e2050726f706f73652074686520707269636520776869636820697320746865206c6173742074726164656420636c6f73696e672070726963652066726f6d207468652076616c756573206c69737420696e2074686520726573706f6e7365206a736f6e2e22000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
35 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000065660070
Arg [2] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [3] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [4] : 0000000000000000000000000467d3b8d17e412194429044def3a27a06a8a51a
Arg [5] : 00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c3
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 4e554d45524943414c0000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [9] : 000000000000000000000000000000000000000000000000000000000044aa20
Arg [10] : 0000000000000000000000000000000000000000000000000000000005f5e100
Arg [11] : 000000000000000000000000000000000000000000000000000000000002a300
Arg [12] : 00000000000000000000000000000000000000000000000010a741a462780000
Arg [13] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [14] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [15] : 0000000000000000000000000000000000000000000000000853a0d2313c0000
Arg [16] : 000000000000000000000000f05c8984a9f9cc5d3981d852331895220d09cdc8
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000205
Arg [18] : 73796e746849443a20225654222c20713a225369676e7570206f6e2068747470
Arg [19] : 733a2f2f7477656c7665646174612e636f6d2f20616e64206765742061206672
Arg [20] : 656520415049206b65792e20517565727920746869732075726c206874747073
Arg [21] : 3a2f2f6170692e7477656c7665646174612e636f6d2f74696d655f7365726965
Arg [22] : 733f6170696b65793d4150495f4b455926696e74657276616c3d31356d696e26
Arg [23] : 74696d657a6f6e653d555443266f726465723d4153432673796d626f6c3d5654
Arg [24] : 2673746172745f646174653d53544152545f4441544526656e645f646174653d
Arg [25] : 454e445f444154453b5265706c61636520746865204150495f4b455920776974
Arg [26] : 6820796f757220617069206b65792e205265706c6163652074686520454e445f
Arg [27] : 4441544520776974682074686520646174652066726f6d207468652072657175
Arg [28] : 6573742074696d657374616d7020696e20595959592d4d4d2d44442048483a6d
Arg [29] : 6d3a737320666f726d617420616e64207265706c616365207468652053544152
Arg [30] : 545f4441544520617320454e445f44415445206d696e7573203420646179732e
Arg [31] : 2050726f706f7365207468652070726963652077686963682069732074686520
Arg [32] : 6c6173742074726164656420636c6f73696e672070726963652066726f6d2074
Arg [33] : 68652076616c756573206c69737420696e2074686520726573706f6e7365206a
Arg [34] : 736f6e2e22000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

This is the Expiring Multi Party (EMP) contract for the Vanguard Total World Stock ETF (cVT) synthetic token that is minted using the Sumero Finance protocol.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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