false
true
0

Contract Address Details

0xF525C7630f292ba26A7cF1019ff74d4176Fa3EAf

Contract Name
VaultUtils
Creator
0x64e7ff–1c04a3 at 0x8d22cf–1190c9
Balance
0 PLS
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
25677529
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
VaultUtils




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
EVM Version
istanbul




Verified at
2024-06-07T07:01:41.100333Z

contracts/protocol/libraries/utils/VaultUtils.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "../../../dependencies/openzeppelin/contracts/IERC20.sol";
import "../../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../../interfaces/IAddressesProvider.sol";
import "../../../interfaces/IVault.sol";
import "../../../interfaces/IVaultConfigurator.sol";
import "../../../interfaces/IPhamePriceOracle.sol";
import "../helpers/Errors.sol";

library VaultUtils {
    using SafeMath for uint256;

    struct Position {
        uint256 size;
        uint256 collateral;
        uint256 averagePrice;
        uint256 entryFundingRate;
        uint256 reserveAmount;
        int256 realisedPnl;
        uint256 lastIncreasedTime;
    }

    uint256 public constant BASIS_POINTS_DIVISOR = 10000;
    uint256 public constant FUNDING_RATE_PRECISION = 1000000;

    function validateLiquidation(
        IAddressesProvider addressesProvider,
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        bool _raise
    ) public view returns (uint256, uint256) {
        IVault vault = IVault(addressesProvider.getVault());

        Position memory position = _getPosition(
            vault,
            _account,
            _collateralToken,
            _indexToken,
            _isLong
        );

        (bool hasProfit, uint256 delta) = vault.getDelta(
            _indexToken,
            position.size,
            position.averagePrice,
            _isLong,
            position.lastIncreasedTime
        );
        uint256 marginFees = getFundingFee(
            vault,
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            position.size,
            position.entryFundingRate
        ).add(
                getPositionFee(
                    addressesProvider,
                    _account,
                    _collateralToken,
                    _indexToken,
                    _isLong,
                    position.size
                )
            );

        if (!hasProfit && position.collateral < delta) {
            if (_raise) {
                revert("VaultUtils: losses exceed collateral");
            }
            return (1, marginFees);
        }

        uint256 remainingCollateral = position.collateral;
        if (!hasProfit) {
            remainingCollateral = position.collateral.sub(delta);
        }

        if (remainingCollateral < marginFees) {
            if (_raise) {
                revert("VaultUtils: fees exceed collateral");
            }
            // cap the fees to the remainingCollateral
            return (1, remainingCollateral);
        }

        DataTypes.VaultConfig memory vaultConfig = IVault(
            addressesProvider.getVault()
        ).getVaultConfig();
        if (
            remainingCollateral < marginFees.add(vaultConfig.liquidationFeeUsd)
        ) {
            if (_raise) {
                revert("VaultUtils: liquidation fees exceed collateral");
            }
            return (1, marginFees);
        }

        if (
            remainingCollateral.mul(vaultConfig.maxLeverage) <
            position.size.mul(BASIS_POINTS_DIVISOR)
        ) {
            if (_raise) {
                revert("VaultUtils: maxLeverage exceeded");
            }
            return (2, marginFees);
        }

        return (0, marginFees);
    }

    function getNextFundingRate(
        IAddressesProvider addressesProvider,
        address _token
    ) public view returns (uint256) {
        IVault vault = IVault(addressesProvider.getVault());
        DataTypes.TokenConfig memory tokenConfig = vault.getTokenConfig(_token);

        uint256 fundingInterval = tokenConfig.fundingInterval;

        if (
            vault.lastFundingTimes(_token).add(fundingInterval) >
            block.timestamp
        ) {
            return 0;
        }

        uint256 intervals = block
            .timestamp
            .sub(vault.lastFundingTimes(_token))
            .div(fundingInterval);
        uint256 poolAmount = vault.poolAmounts(_token);
        if (poolAmount == 0) {
            return 0;
        }

        return
            tokenConfig
                .fundingRateFactor
                .mul(vault.reservedAmounts(_token))
                .mul(intervals)
                .div(poolAmount);
    }

    function getPositionFee(
        IAddressesProvider addressesProvider,
        address /* _account */,
        address /* _collateralToken */,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) public view returns (uint256) {
        if (_sizeDelta == 0) {
            return 0;
        }

        DataTypes.TokenConfig memory tokenConfig = IVault(
            addressesProvider.getVault()
        ).getTokenConfig(_indexToken);
        uint256 afterFeeUsd = _sizeDelta
            .mul(
                BASIS_POINTS_DIVISOR.sub(
                    _isLong
                        ? tokenConfig.longMarginFeeBps
                        : tokenConfig.shortMarginFeeBps
                )
            )
            .div(BASIS_POINTS_DIVISOR);
        return _sizeDelta.sub(afterFeeUsd);
    }

    function getFundingFee(
        IVault vault,
        address /* _account */,
        address _collateralToken,
        address /* _indexToken */,
        bool /* _isLong */,
        uint256 _size,
        uint256 _entryFundingRate
    ) public view returns (uint256) {
        if (_size == 0) {
            return 0;
        }

        uint256 fundingRate = vault
            .cumulativeFundingRates(_collateralToken)
            .sub(_entryFundingRate);
        if (fundingRate == 0) {
            return 0;
        }

        return _size.mul(fundingRate).div(FUNDING_RATE_PRECISION);
    }

    function getBuyUsdphFeeBps(
        IAddressesProvider addressesProvider,
        address _token,
        uint256 _usdphAmount
    ) public view returns (uint256) {
        DataTypes.VaultConfig memory vaultConfig = IVault(
            addressesProvider.getVault()
        ).getVaultConfig();
        return
            getFeeBps(
                addressesProvider,
                _token,
                _usdphAmount,
                vaultConfig.mintBurnFeeBps,
                vaultConfig.taxBps,
                true
            );
    }

    function getSellUsdphFeeBps(
        IAddressesProvider addressesProvider,
        address _token,
        uint256 _usdphAmount
    ) public view returns (uint256) {
        DataTypes.VaultConfig memory vaultConfig = IVault(
            addressesProvider.getVault()
        ).getVaultConfig();
        return
            getFeeBps(
                addressesProvider,
                _token,
                _usdphAmount,
                vaultConfig.mintBurnFeeBps,
                vaultConfig.taxBps,
                false
            );
    }

    function getSwapFeeBps(
        IAddressesProvider addressesProvider,
        address _tokenIn,
        address _tokenOut,
        uint256 _usdphAmount
    ) public view returns (uint256) {
        IVault vault = IVault(addressesProvider.getVault());
        (uint256 baseBps, uint256 taxBps) = IVaultConfigurator(
            addressesProvider.getVaultConfigurator()
        ).getSwapFeeAndTaxBps(
                vault.getTokenConfig(_tokenIn).isStable &&
                    vault.getTokenConfig(_tokenOut).isStable
            );
        uint256 feesBps0 = getFeeBps(
            addressesProvider,
            _tokenIn,
            _usdphAmount,
            baseBps,
            taxBps,
            true
        );
        uint256 feesBps1 = getFeeBps(
            addressesProvider,
            _tokenOut,
            _usdphAmount,
            baseBps,
            taxBps,
            false
        );
        // use the higher of the two fee basis points
        return feesBps0 > feesBps1 ? feesBps0 : feesBps1;
    }

    // cases to consider
    // 1. initialAmount is far from targetAmount, action increases balance slightly => high rebate
    // 2. initialAmount is far from targetAmount, action increases balance largely => high rebate
    // 3. initialAmount is close to targetAmount, action increases balance slightly => low rebate
    // 4. initialAmount is far from targetAmount, action reduces balance slightly => high tax
    // 5. initialAmount is far from targetAmount, action reduces balance largely => high tax
    // 6. initialAmount is close to targetAmount, action reduces balance largely => low tax
    // 7. initialAmount is above targetAmount, nextAmount is below targetAmount and vice versa
    // 8. a large swap should have similar fees as the same trade split into multiple smaller swaps
    function getFeeBps(
        IAddressesProvider addressesProvider,
        address _token,
        uint256 _usdphDelta,
        uint256 _feeBps,
        uint256 _taxBps,
        bool _increment
    ) public view returns (uint256) {
        if (
            !IVault(addressesProvider.getVault())
                .getVaultConfig()
                .hasDynamicFees
        ) {
            return _feeBps;
        }

        uint256 initialAmount = IVault(addressesProvider.getVault())
            .usdphAmounts(_token);
        uint256 nextAmount = initialAmount.add(_usdphDelta);
        if (!_increment) {
            nextAmount = _usdphDelta > initialAmount
                ? 0
                : initialAmount.sub(_usdphDelta);
        }

        uint256 targetAmount = _getTargetUsdphAmount(addressesProvider, _token);
        if (targetAmount == 0) {
            return _feeBps;
        }

        uint256 initialDiff = initialAmount > targetAmount
            ? initialAmount.sub(targetAmount)
            : targetAmount.sub(initialAmount);
        uint256 nextDiff = nextAmount > targetAmount
            ? nextAmount.sub(targetAmount)
            : targetAmount.sub(nextAmount);

        // action improves relative asset balance
        if (nextDiff < initialDiff) {
            uint256 rebateBps = _taxBps.mul(initialDiff).div(targetAmount);
            return rebateBps > _feeBps ? 0 : _feeBps.sub(rebateBps);
        }

        uint256 averageDiff = initialDiff.add(nextDiff).div(2);
        if (averageDiff > targetAmount) {
            averageDiff = targetAmount;
        }
        uint256 taxBps = _taxBps.mul(averageDiff).div(targetAmount);
        return _feeBps.add(taxBps);
    }

    function _getMinProfitTime(
        DataTypes.TokenConfig memory tokenConfig,
        uint256 _size,
        bool _isLong
    ) private pure returns (uint256) {
        if (_size == 0 || tokenConfig.minProfitTime == 0) {
            return 0;
        }
        uint256 baseSize = _isLong
            ? tokenConfig.maxPositionLongSize
            : tokenConfig.maxPositionShortSize;
        if (baseSize == 0) {
            return tokenConfig.minProfitTime;
        }
        if (
            (tokenConfig.hasMinProfitTimeFloor && _size < baseSize) ||
            (_size == baseSize)
        ) {
            return tokenConfig.minProfitTime;
        }

        if (_size < baseSize) {
            return tokenConfig.minProfitTime.mul(_size).div(baseSize);
        } else {
            return
                tokenConfig
                    .minProfitTime
                    .mul(
                        baseSize.mul(10000).add(
                            _size.sub(baseSize).mul(
                                tokenConfig.minProfitTimeCoefBps
                            )
                        )
                    )
                    .div(baseSize)
                    .div(10000);
        }
    }

    function getMinProfitTime(
        IAddressesProvider addressesProvider,
        address _indexToken,
        uint256 _size,
        bool _isLong
    ) public view returns (uint256) {
        DataTypes.TokenConfig memory tokenConfig = IVault(
            addressesProvider.getVault()
        ).getTokenConfig(_indexToken);
        return _getMinProfitTime(tokenConfig, _size, _isLong);
    }

    function getDelta(
        IAddressesProvider addressesProvider,
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) public view returns (bool, uint256) {
        require(_averagePrice > 0, Errors.VU_INVALID_AVERAGE_PRICE);
        uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
            .getPrice(_indexToken, !_isLong);
        uint256 priceDelta = _averagePrice > price
            ? _averagePrice.sub(price)
            : price.sub(_averagePrice);
        uint256 delta = _size.mul(priceDelta).div(_averagePrice);

        bool hasProfit;

        if (_isLong) {
            hasProfit = price > _averagePrice;
        } else {
            hasProfit = _averagePrice > price;
        }

        // if the minProfitTime has passed then there will be no min profit threshold
        // the min profit threshold helps to prevent front-running issues
        DataTypes.TokenConfig memory tokenConfig = IVault(
            addressesProvider.getVault()
        ).getTokenConfig(_indexToken);
        uint256 minBps = block.timestamp >
            _lastIncreasedTime.add(
                _getMinProfitTime(tokenConfig, _size, _isLong)
            )
            ? 0
            : tokenConfig.minProfitBps;
        if (hasProfit && delta.mul(BASIS_POINTS_DIVISOR) <= _size.mul(minBps)) {
            delta = 0;
        }

        return (hasProfit, delta);
    }

    function _getPosition(
        IVault vault,
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    ) private view returns (Position memory) {
        Position memory position;
        {
            (
                uint256 size,
                uint256 collateral,
                uint256 averagePrice,
                uint256 entryFundingRate /* reserveAmount */ /* realisedPnl */ /* hasProfit */,
                ,
                ,
                ,
                uint256 lastIncreasedTime
            ) = vault.getPosition(
                    _account,
                    _collateralToken,
                    _indexToken,
                    _isLong
                );
            position.size = size;
            position.collateral = collateral;
            position.averagePrice = averagePrice;
            position.entryFundingRate = entryFundingRate;
            position.lastIncreasedTime = lastIncreasedTime;
        }
        return position;
    }

    function _getTargetUsdphAmount(
        IAddressesProvider addressesProvider,
        address _token
    ) private view returns (uint256) {
        uint256 supply = IERC20(addressesProvider.getUsdph()).totalSupply();
        if (supply == 0) {
            return 0;
        }
        IVault vault = IVault(addressesProvider.getVault());
        uint256 weight = vault.getTokenConfig(_token).weight;
        return weight.mul(supply).div(vault.totalTokenWeights());
    }
}
        

contracts/dependencies/openzeppelin/contracts/IERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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
    );
}
          

contracts/protocol/libraries/helpers/Errors.sol

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;

library Errors {
    string public constant VC_INVALID_STAKING_BPS = "1"; // VaultConfigurator: invalid stakingBps
    string public constant VC_INVALID_MAX_LEVERAGE = "2"; // VaultConfigurator: invalid maxLeverage
    string public constant VC_INVALID_TAX_BPS = "3"; // VaultConfigurator: invalid taxBps
    string public constant VC_INVALID_STABLE_TAX_BPS = "4"; // VaultConfigurator: invalid stableTaxBps
    string public constant VC_INVALID_MINT_BURN_FEE_BPS = "5"; // VaultConfigurator: invalid mintBurnFeeBps
    string public constant VC_INVALID_SWAP_FEE_BPS = "6"; // VaultConfigurator: invalid swapFeeBps
    string public constant VC_INVALID_STABLE_SWAP_FEE_BPS = "7"; // VaultConfigurator: invalid stableSwapFeeBps
    string public constant VC_INVALID_MARGIN_FEE_BPS = "8"; // VaultConfigurator: invalid marginFeeBps
    string public constant VC_INVALID_LIQUIDATION_FEE_USD = "9"; // VaultConfigurator: invalid _liquidationFeeUsd
    string public constant VC_INVALID_FUNDING_INTERVAL = "10"; // VaultConfigurator: invalid fundingInterval
    string public constant VC_INVALID_FUNDING_RATE_FACTOR = "11"; // VaultConfigurator: invalid fundingRateFactor
    string public constant VC_TOKEN_NOT_WHITELISTED = "13"; // VaultConfigurator: token not whitelisted
    string public constant VC_INVALID_MIN_PROFIT_TIME_COEF_BPS = "16"; // VaultConfigurator: invalid minProfitTimeCoefBps

    string public constant VU_INVALID_AVERAGE_PRICE = "38"; // VaultUtil: invalid averagePrice
    string public constant VU_INVALID_MSG_SENDER = "41"; // VaultUtil: invalid msg.sender

    string public constant TCL_MISMATCHED_TOKENS = "42"; // TokenConfigsLogic: mismatched tokens
    string public constant TCL_COLLATERAL_TOKEN_NOT_WHITELISTED = "43"; // TokenConfigsLogic: collateralToken not whitelisted
    string public constant TCL_COLLATERAL_TOKEN_MUST_NOT_BE_STABLE = "44"; // TokenConfigsLogic: collateralToken must not be a stableToken
    string public constant TCL_COLLATERAL_TOKEN_MUST_BE_STABLE = "46"; // TokenConfigsLogic: collateralToken must be a stableToken
    string public constant TCL_INDEX_TOKEN_MUST_NOT_BE_STABLE = "47"; // TokenConfigsLogic: indexToken must not be a stableToken
    string public constant TCL_INDEX_TOKEN_NOT_SHORTABLE = "48"; // TokenConfigsLogic: indexToken not shortable
    string public constant TCL_TOKEN_NOT_WHITELISTED = "200"; // TokenConfigsLogic: token not whitelisted
    string public constant TCL_INVALID_TOKEN_WEIGHT = "201"; // TokenConfigsLogic: invalid token weight
}
          

contracts/dependencies/openzeppelin/contracts/SafeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
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)
    {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        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)
    {
        // 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)
    {
        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)
    {
        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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        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) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @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. 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) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        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) {
        require(b > 0, "SafeMath: modulo by zero");
        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) {
        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.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * 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) {
        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) {
        require(b > 0, errorMessage);
        return a % b;
    }
}
          

contracts/interfaces/IAddressesProvider.sol

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;

interface IAddressesProvider {
    function getUsdph() external view returns (address);

    function getPhlp() external view returns (address);

    function getPhlpManager() external view returns (address);

    function getVault() external view returns (address);

    function getVaultConfigurator() external view returns (address);

    function getRouter() external view returns (address);

    function getOrderBook() external view returns (address);

    function getPositionManager() external view returns (address);

    function getPositionRouter() external view returns (address);

    function getPriceOracle() external view returns (address);

    function getShortsTracker() external view returns (address);

    function getTreasury() external view returns (address payable);

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

contracts/interfaces/IPhamePriceOracle.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPhamePriceOracle {
    function backupPriceOracle() external view returns (address);

    function adjustmentBps(address _token) external view returns (uint256);

    function isAdjustmentAdditive(address _token) external view returns (bool);

    function setAdjustment(
        address _token,
        bool _isAdditive,
        uint256 _adjustmentBps
    ) external;

    function setSpreadBps(address _token, uint256 _spreadBps) external;

    function setSpreadThresholdBps(uint256 _spreadThresholdBps) external;

    function setPriceSampleSpace(uint256 _priceSampleSpace) external;

    function setMaxStrictPriceDeviation(
        uint256 _maxStrictPriceDeviation
    ) external;

    function getPrice(
        address _token,
        bool _maximise
    ) external view returns (uint256);

    function setTokenConfig(
        address _token,
        address _priceFeed,
        uint256 _priceDecimals,
        bool _isStrictStable
    ) external;
}
          

contracts/interfaces/IVault.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "../protocol/libraries/types/DataTypes.sol";
import "./IAddressesProvider.sol";

interface IVault {
    struct Position {
        uint256 size;
        uint256 collateral;
        uint256 averagePrice;
        uint256 entryFundingRate;
        uint256 reserveAmount;
        int256 realisedPnl;
        uint256 lastIncreasedTime;
    }

    event BuyUSDPH(
        address account,
        address token,
        uint256 tokenAmount,
        uint256 usdphAmount,
        uint256 feeBps
    );
    event SellUSDPH(
        address account,
        address token,
        uint256 usdphAmount,
        uint256 tokenAmount,
        uint256 feeBps
    );
    event Swap(
        address account,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        uint256 amountOutAfterFees,
        uint256 feeBps
    );
    event IncreasePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong,
        uint256 price,
        uint256 fee
    );
    event DecreasePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong,
        uint256 price,
        uint256 fee
    );
    event LiquidatePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        bool isLong,
        uint256 size,
        uint256 collateral,
        uint256 reserveAmount,
        int256 realisedPnl,
        uint256 markPrice
    );
    event UpdatePosition(
        bytes32 key,
        uint256 size,
        uint256 collateral,
        uint256 averagePrice,
        uint256 entryFundingRate,
        uint256 reserveAmount,
        int256 realisedPnl,
        uint256 markPrice
    );
    event ClosePosition(
        bytes32 key,
        uint256 size,
        uint256 collateral,
        uint256 averagePrice,
        uint256 entryFundingRate,
        uint256 reserveAmount,
        int256 realisedPnl
    );

    event UpdateFundingRate(address token, uint256 fundingRate);
    event UpdatePnl(bytes32 key, bool hasProfit, uint256 delta);

    event CollectSwapFees(address token, uint256 feeUsd, uint256 feeTokens);
    event CollectMarginFees(address token, uint256 feeUsd, uint256 feeTokens);
    event PayLpFees(address token, uint256 feeTokens);

    event DirectPoolDeposit(address token, uint256 amount);
    event IncreasePoolAmount(address token, uint256 amount);
    event DecreasePoolAmount(address token, uint256 amount);
    event IncreaseUsdphAmount(address token, uint256 amount);
    event DecreaseUsdphAmount(address token, uint256 amount);
    event IncreaseReservedAmount(address token, uint256 amount);
    event DecreaseReservedAmount(address token, uint256 amount);
    event IncreaseGuaranteedUsd(address token, uint256 amount);
    event DecreaseGuaranteedUsd(address token, uint256 amount);

    function addressesProvider() external view returns (IAddressesProvider);

    function getVaultConfig()
        external
        view
        returns (DataTypes.VaultConfig memory);

    function setVaultConfig(
        DataTypes.VaultConfig calldata vaultConfig
    ) external;

    function allWhitelistedTokensLength() external view returns (uint256);

    function totalTokenWeights() external view returns (uint256);

    function allWhitelistedTokens(uint256) external view returns (address);

    function getTokenConfig(
        address _token
    ) external view returns (DataTypes.TokenConfig memory);

    function setTokenConfig(
        address _token,
        DataTypes.TokenConfig calldata tokenConfig
    ) external;

    function clearTokenConfig(address _token) external;

    function getAccountTokenConfig(
        address _account,
        address _token
    ) external view returns (DataTypes.AccountTokenConfig memory);

    function setAccountTokenConfig(
        address _account,
        address _token,
        DataTypes.AccountTokenConfig calldata accountTokenConfig
    ) external;

    function getAccountTokenPositionSizeLimit(
        address _account,
        address _token,
        bool _isLong
    ) external view returns (uint256);

    function setUsdphAmount(address _token, uint256 _amount) external;

    function tokenBalances(address _token) external view returns (uint256);

    function lastFundingTimes(address _token) external view returns (uint256);

    function withdrawFees(
        address _token,
        address _receiver
    ) external returns (uint256);

    function directPoolDeposit(address _token) external;

    function buyUSDPH(
        address _token,
        address _receiver
    ) external returns (uint256);

    function buyUSDPHwithoutFee(address _token) external returns (uint256);

    function sellUSDPH(
        address _token,
        address _receiver
    ) external returns (uint256);

    function swap(
        address _tokenIn,
        address _tokenOut,
        address _receiver
    ) external returns (uint256);

    function increasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external;

    function decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external returns (uint256);

    function validateLiquidation(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        bool _raise
    ) external view returns (uint256, uint256);

    function liquidatePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        address _feeReceiver
    ) external;

    function tokenToUsdMin(
        address _token,
        uint256 _tokenAmount
    ) external view returns (uint256);

    function cumulativeFundingRates(
        address _token
    ) external view returns (uint256);

    function getNextFundingRate(address _token) external view returns (uint256);

    function getFeeBps(
        address _token,
        uint256 _usdphDelta,
        uint256 _feeBps,
        uint256 _taxBps,
        bool _increment
    ) external view returns (uint256);

    function feeReserves(address _token) external view returns (uint256);

    function globalShortSizes(address _token) external view returns (uint256);

    function guaranteedUsd(address _token) external view returns (uint256);

    function poolAmounts(address _token) external view returns (uint256);

    function reservedAmounts(address _token) external view returns (uint256);

    function usdphAmounts(address _token) external view returns (uint256);

    function getRedemptionAmount(
        address _token,
        uint256 _usdphAmount
    ) external view returns (uint256);

    function getMinProfitTime(
        address _indexToken,
        uint256 _size,
        bool _isLong
    ) external view returns (uint256);

    function getDelta(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) external view returns (bool, uint256);

    function getPosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    )
        external
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            bool,
            uint256
        );
}
          

contracts/interfaces/IVaultConfigurator.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

interface IVaultConfigurator {
    function setIsLeverageEnabled(bool _isLeverageEnabled) external;

    function setStakingBps(uint256 _stakingBps) external;

    function setUsdphAmount(address _token, uint256 _amount) external;

    function setTokenConfig(
        address _token,
        uint256 _tokenDecimals,
        uint256 _tokenWeight,
        uint256 _maxUsdphAmount,
        bool _isStable,
        bool _isShortable
    ) external;

    function setTokenMinProfit(
        address _token,
        uint256 _minProfitBps,
        uint256 _minProfitTime,
        bool _hasMinProfitTimeFloor,
        uint256 _minProfitTimeCoefBps
    ) external;

    function setTokenMaxSizes(
        address _token,
        uint256 maxGlobalLongSize,
        uint256 maxGlobalShortSize,
        uint256 maxPositionLongSize,
        uint256 maxPositionShortSize
    ) external;

    function setAccountTokenConfig(
        address _account,
        address _token,
        bool _isLongBlacklisted,
        bool _isShortBlacklisted,
        uint256 _maxPositionLongSizeOverride,
        uint256 _maxPositionShortSizeOverride
    ) external;

    function getSwapFeeAndTaxBps(
        bool isStableSwap
    ) external view returns (uint256, uint256);
}
          

contracts/protocol/libraries/types/DataTypes.sol

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.6;

library DataTypes {
    struct VaultConfig {
        bool isSwapEnabled;
        bool isLeverageEnabled;
        uint256 maxLeverage;
        // fees
        uint256 taxBps;
        uint256 stableTaxBps;
        uint256 mintBurnFeeBps;
        uint256 swapFeeBps;
        uint256 stableSwapFeeBps;
        uint256 liquidationFeeUsd;
        bool hasDynamicFees;
        // staking
        uint256 stakingBps;
    }

    struct TokenConfig {
        // should always be true if token exists
        bool isWhitelisted;
        // basic parameters
        uint256 decimals;
        uint256 weight; // customisation of index composition
        uint256 minProfitBps;
        uint256 minProfitTime;
        bool hasMinProfitTimeFloor;
        uint256 minProfitTimeCoefBps; // coefficient for minProfitTime
        uint256 maxUsdphAmount; // a max amount of USDPH debt for a token
        bool isStable;
        bool isShortable;
        // risk parameters
        // bufferAmount allows specification of an amount to exclude from swaps
        // this can be used to ensure a certain amount of liquidity is available for leverage positions
        uint256 bufferAmount;
        uint256 maxGlobalLongSize;
        uint256 maxGlobalShortSize;
        uint256 maxPositionLongSize;
        uint256 maxPositionShortSize;
        // fees
        uint256 longMarginFeeBps;
        uint256 shortMarginFeeBps;
        // funding rate
        uint256 fundingInterval;
        uint256 fundingRateFactor;
    }

    struct TokenConfigs {
        uint256 totalTokenWeights;
        address[] allWhitelistedTokens;
        mapping(address => TokenConfig) tokenConfigs;
    }

    struct AccountTokenConfig {
        bool isLongBlacklisted;
        bool isShortBlacklisted;
        uint256 maxPositionLongSizeOverride;
        uint256 maxPositionShortSizeOverride;
    }
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"istanbul"}
              

Contract ABI

[{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BASIS_POINTS_DIVISOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"FUNDING_RATE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBuyUsdphFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDelta","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_averagePrice","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_lastIncreasedTime","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphDelta","internalType":"uint256"},{"type":"uint256","name":"_feeBps","internalType":"uint256"},{"type":"uint256","name":"_taxBps","internalType":"uint256"},{"type":"bool","name":"_increment","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFundingFee","inputs":[{"type":"IVault","name":"vault","internalType":"contract IVault"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_entryFundingRate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getMinProfitTime","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNextFundingRate","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPositionFee","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSellUsdphFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSwapFeeBps","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_tokenIn","internalType":"address"},{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"validateLiquidation","inputs":[{"type":"IAddressesProvider","name":"addressesProvider","internalType":"contract IAddressesProvider"},{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"bool","name":"_raise","internalType":"bool"}]}]
              

Contract Creation Code

0x6124e7610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100bd5760003560e01c80638e65d2c61161007b5780638e65d2c614610142578063ac56fc0e14610155578063c1a83e2a14610168578063cfb90b201461017b578063d4b9aa631461019c578063dbeac656146101af576100bd565b80628d73e6146100c2578063126082cf146100eb57806323a0ec04146100f35780634e9c9175146101065780636be6026b1461012757806387e35c2c1461012f575b600080fd5b6100d56100d0366004611c9f565b6101c2565b6040516100e2919061242f565b60405180910390f35b6100d561052a565b6100d5610101366004611f03565b610530565b610119610114366004611cd7565b610837565b6040516100e2929190612438565b6100d5610bc8565b6100d561013d366004611dd0565b610bcf565b6100d5610150366004611e60565b610e85565b6100d5610163366004611e20565b610f82565b6100d5610176366004611e20565b61108b565b61018e610189366004611eb2565b611189565b6040516100e29291906122c3565b6100d56101aa366004611d58565b611465565b6100d56101bd366004611f5b565b6115b3565b600080836001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156101fe57600080fd5b505afa158015610212573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102369190611c56565b90506000816001600160a01b031663cb67e3b1856040518263ffffffff1660e01b8152600401610266919061222f565b6102606040518083038186803b15801561027f57600080fd5b505afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b79190611fdd565b9050600081610220015190504261034a82856001600160a01b031663d8f897c3896040518263ffffffff1660e01b81526004016102f4919061222f565b60206040518083038186803b15801561030c57600080fd5b505afa158015610320573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610344919061218b565b9061167b565b111561035c5760009350505050610524565b60006103ee826103e8866001600160a01b031663d8f897c38a6040518263ffffffff1660e01b8152600401610391919061222f565b60206040518083038186803b1580156103a957600080fd5b505afa1580156103bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e1919061218b565b42906116d5565b90611732565b90506000846001600160a01b03166352f55eed886040518263ffffffff1660e01b815260040161041e919061222f565b60206040518083038186803b15801561043657600080fd5b505afa15801561044a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046e919061218b565b90508061048357600095505050505050610524565b61051c816103e884610516896001600160a01b031663c3c7b9e98d6040518263ffffffff1660e01b81526004016104ba919061222f565b60206040518083038186803b1580156104d257600080fd5b505afa1580156104e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050a919061218b565b6102408a015190611799565b90611799565b955050505050505b92915050565b61271081565b6000866001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561056b57600080fd5b505afa15801561057f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a39190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b1580156105dc57600080fd5b505afa1580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061491906120e3565b610120015161062457508261082d565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561065f57600080fd5b505afa158015610673573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106979190611c56565b6001600160a01b03166342e85182886040518263ffffffff1660e01b81526004016106c2919061222f565b60206040518083038186803b1580156106da57600080fd5b505afa1580156106ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610712919061218b565b90506000610720828861167b565b9050836107435781871161073d5761073882886116d5565b610740565b60005b90505b600061074f8a8a6117f2565b9050806107615786935050505061082d565b60008184116107795761077482856116d5565b610783565b61078384836116d5565b9050600082841161079d5761079883856116d5565b6107a7565b6107a784846116d5565b9050818110156107e95760006107c1846103e88b86611799565b90508981116107d9576107d48a826116d5565b6107dc565b60005b965050505050505061082d565b60006107fa60026103e8858561167b565b9050838111156108075750825b6000610817856103e88c85611799565b90506108238b8261167b565b9750505050505050505b9695505050505050565b6000806000886001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190611c56565b905060006108be828a8a8a8a611a5f565b805160408083015160c08401519151635c07eaab60e01b815293945060009384936001600160a01b03881693635c07eaab93610901938f93928f91600401612288565b604080518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109509190611c72565b91509150600061098261096b8e8e8e8e8e8a60000151611465565b610344878f8f8f8f8b600001518c606001516115b3565b9050821580156109955750818460200151105b156109d15787156109c15760405162461bcd60e51b81526004016109b890612326565b60405180910390fd5b600196509450610bbd9350505050565b6020840151836109ed5760208501516109ea90846116d5565b90505b81811015610a24578815610a135760405162461bcd60e51b81526004016109b8906123ed565b600197509550610bbd945050505050565b60008e6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5f57600080fd5b505afa158015610a73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a979190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b158015610ad057600080fd5b505afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0891906120e3565b9050610b228161010001518461167b90919063ffffffff16565b821015610b5a578915610b475760405162461bcd60e51b81526004016109b89061239f565b6001839850985050505050505050610bbd565b8551610b6890612710611799565b6040820151610b78908490611799565b1015610baf578915610b9c5760405162461bcd60e51b81526004016109b89061236a565b6002839850985050505050505050610bbd565b506000975090955050505050505b965096945050505050565b620f424081565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610c0b57600080fd5b505afa158015610c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c439190611c56565b9050600080876001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c8157600080fd5b505afa158015610c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb99190611c56565b6001600160a01b031663eab4d7a9846001600160a01b031663cb67e3b18a6040518263ffffffff1660e01b8152600401610cf3919061222f565b6102606040518083038186803b158015610d0c57600080fd5b505afa158015610d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d449190611fdd565b61010001518015610dd3575060405163cb67e3b160e01b81526001600160a01b0386169063cb67e3b190610d7c908b9060040161222f565b6102606040518083038186803b158015610d9557600080fd5b505afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190611fdd565b61010001515b6040518263ffffffff1660e01b8152600401610def91906122b8565b604080518083038186803b158015610e0657600080fd5b505afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e91906121a3565b915091506000610e5389898886866001610530565b90506000610e668a898987876000610530565b9050808211610e755780610e77565b815b9a9950505050505050505050565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec157600080fd5b505afa158015610ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef99190611c56565b6001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401610f24919061222f565b6102606040518083038186803b158015610f3d57600080fd5b505afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190611fdd565b905061082d818585611b27565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610fbe57600080fd5b505afa158015610fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff69190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561102f57600080fd5b505afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106791906120e3565b90506110808585858460a0015185606001516000610530565b9150505b9392505050565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156110c757600080fd5b505afa1580156110db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ff9190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561113857600080fd5b505afa15801561114c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117091906120e3565b90506110808585858460a0015185606001516001610530565b6000806000851160405180604001604052806002815260200161066760f31b815250906111c95760405162461bcd60e51b81526004016109b891906122d3565b506000886001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561120557600080fd5b505afa158015611219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123d9190611c56565b6001600160a01b03166376d697608987156040518363ffffffff1660e01b815260040161126b92919061226d565b60206040518083038186803b15801561128357600080fd5b505afa158015611297573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bb919061218b565b905060008187116112d5576112d082886116d5565b6112df565b6112df87836116d5565b905060006112f1886103e88b85611799565b9050600087156113045750878311611309565b508288115b60008c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561134457600080fd5b505afa158015611358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137c9190611c56565b6001600160a01b031663cb67e3b18d6040518263ffffffff1660e01b81526004016113a7919061222f565b6102606040518083038186803b1580156113c057600080fd5b505afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f89190611fdd565b9050600061141161140a838e8d611b27565b8a9061167b565b4211611421578160600151611424565b60005b905082801561144757506114388c82611799565b61144485612710611799565b11155b1561145157600093505b50909c919b50909950505050505050505050565b6000816114745750600061082d565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156114af57600080fd5b505afa1580156114c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190611c56565b6001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401611512919061222f565b6102606040518083038186803b15801561152b57600080fd5b505afa15801561153f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115639190611fdd565b9050600061159a6127106103e8611593886115835785610200015161158a565b856101e001515b612710906116d5565b8790611799565b90506115a684826116d5565b9998505050505050505050565b6000826115c257506000611670565b600061164a838a6001600160a01b031663c65bc7b18a6040518263ffffffff1660e01b81526004016115f4919061222f565b60206040518083038186803b15801561160c57600080fd5b505afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611644919061218b565b906116d5565b90508061165b576000915050611670565b61166c620f42406103e88684611799565b9150505b979650505050505050565b600082820183811015611084576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008282111561172c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211611788576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161179157fe5b049392505050565b6000826117a857506000610524565b828202828482816117b557fe5b04146110845760405162461bcd60e51b81526004018080602001828103825260218152602001806124916021913960400191505060405180910390fd5b600080836001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561182e57600080fd5b505afa158015611842573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118669190611c56565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189e57600080fd5b505afa1580156118b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d6919061218b565b9050806118e7576000915050610524565b6000846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561192257600080fd5b505afa158015611936573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195a9190611c56565b90506000816001600160a01b031663cb67e3b1866040518263ffffffff1660e01b815260040161198a919061222f565b6102606040518083038186803b1580156119a357600080fd5b505afa1580156119b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119db9190611fdd565b60400151905061082d826001600160a01b031663dc8f5fac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a1d57600080fd5b505afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a55919061218b565b6103e88386611799565b611a67611c09565b611a6f611c09565b60008060008060008b6001600160a01b0316634a3f088d8c8c8c8c6040518563ffffffff1660e01b8152600401611aa99493929190612243565b6101006040518083038186803b158015611ac257600080fd5b505afa158015611ad6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afa91906121c6565b968d5250505060208a01929092526040890152606088015260c087015250939a9950505050505050505050565b6000821580611b3857506080840151155b15611b4557506000611084565b600082611b5757846101c00151611b5e565b846101a001515b905080611b715750506080830151611084565b8460a001518015611b8157508084105b80611b8b57508084145b15611b9c5750506080830151611084565b80841015611bc757611bbf816103e886886080015161179990919063ffffffff16565b915050611084565b611bbf6127106103e8836103e8611bfe611bf28b60c00151610516898d6116d590919063ffffffff16565b61034488612710611799565b60808b015190611799565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8051611c5181612482565b919050565b600060208284031215611c67578081fd5b81516110848161246a565b60008060408385031215611c84578081fd5b8251611c8f81612482565b6020939093015192949293505050565b60008060408385031215611cb1578182fd5b8235611cbc8161246a565b91506020830135611ccc8161246a565b809150509250929050565b60008060008060008060c08789031215611cef578182fd5b8635611cfa8161246a565b95506020870135611d0a8161246a565b94506040870135611d1a8161246a565b93506060870135611d2a8161246a565b92506080870135611d3a81612482565b915060a0870135611d4a81612482565b809150509295509295509295565b60008060008060008060c08789031215611d70578182fd5b8635611d7b8161246a565b95506020870135611d8b8161246a565b94506040870135611d9b8161246a565b93506060870135611dab8161246a565b92506080870135611dbb81612482565b8092505060a087013590509295509295509295565b60008060008060808587031215611de5578384fd5b8435611df08161246a565b93506020850135611e008161246a565b92506040850135611e108161246a565b9396929550929360600135925050565b600080600060608486031215611e34578081fd5b8335611e3f8161246a565b92506020840135611e4f8161246a565b929592945050506040919091013590565b60008060008060808587031215611e75578182fd5b8435611e808161246a565b93506020850135611e908161246a565b9250604085013591506060850135611ea781612482565b939692955090935050565b60008060008060008060c08789031215611eca578384fd5b8635611ed58161246a565b95506020870135611ee58161246a565b945060408701359350606087013592506080870135611dbb81612482565b60008060008060008060c08789031215611f1b578384fd5b8635611f268161246a565b95506020870135611f368161246a565b945060408701359350606087013592506080870135915060a0870135611d4a81612482565b600080600080600080600060e0888a031215611f75578485fd5b8735611f808161246a565b96506020880135611f908161246a565b95506040880135611fa08161246a565b94506060880135611fb08161246a565b93506080880135611fc081612482565b9699959850939692959460a0840135945060c09093013592915050565b6000610260808385031215611ff0578182fd5b611ff981612446565b905061200483611c46565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261203a60a08401611c46565b60a082015260c083015160c082015260e083015160e0820152610100612061818501611c46565b90820152610120612073848201611c46565b908201526101408381015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015261020080840151908201526102208084015190820152610240928301519281019290925250919050565b60006101608083850312156120f6578182fd5b6120ff81612446565b905061210a83611c46565b815261211860208401611c46565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612173818501611c46565b90820152610140928301519281019290925250919050565b60006020828403121561219c578081fd5b5051919050565b600080604083850312156121b5578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b0312156121e2578182fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c089015161221781612482565b8092505060e089015190509295985092959890939650565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039590951685526020850193909352604084019190915215156060830152608082015260a00190565b901515815260200190565b9115158252602082015260400190565b6000602080835283518082850152825b818110156122ff578581018301518582016040015282016122e3565b818111156123105783604083870101525b50601f01601f1916929092016040019392505050565b60208082526024908201527f5661756c745574696c733a206c6f737365732065786365656420636f6c6c6174604082015263195c985b60e21b606082015260800190565b6020808252818101527f5661756c745574696c733a206d61784c65766572616765206578636565646564604082015260600190565b6020808252602e908201527f5661756c745574696c733a206c69717569646174696f6e20666565732065786360408201526d1959590818dbdb1b185d195c985b60921b606082015260800190565b60208082526022908201527f5661756c745574696c733a20666565732065786365656420636f6c6c61746572604082015261185b60f21b606082015260800190565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561246257fe5b604052919050565b6001600160a01b038116811461247f57600080fd5b50565b801515811461247f57600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122050b0025f9b44f4e5dfa35dc924767108eaa667baa2870b32255d3d374c8c923564736f6c63430007060033

Deployed ByteCode

0x73f525c7630f292ba26a7cf1019ff74d4176fa3eaf30146080604052600436106100bd5760003560e01c80638e65d2c61161007b5780638e65d2c614610142578063ac56fc0e14610155578063c1a83e2a14610168578063cfb90b201461017b578063d4b9aa631461019c578063dbeac656146101af576100bd565b80628d73e6146100c2578063126082cf146100eb57806323a0ec04146100f35780634e9c9175146101065780636be6026b1461012757806387e35c2c1461012f575b600080fd5b6100d56100d0366004611c9f565b6101c2565b6040516100e2919061242f565b60405180910390f35b6100d561052a565b6100d5610101366004611f03565b610530565b610119610114366004611cd7565b610837565b6040516100e2929190612438565b6100d5610bc8565b6100d561013d366004611dd0565b610bcf565b6100d5610150366004611e60565b610e85565b6100d5610163366004611e20565b610f82565b6100d5610176366004611e20565b61108b565b61018e610189366004611eb2565b611189565b6040516100e29291906122c3565b6100d56101aa366004611d58565b611465565b6100d56101bd366004611f5b565b6115b3565b600080836001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156101fe57600080fd5b505afa158015610212573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102369190611c56565b90506000816001600160a01b031663cb67e3b1856040518263ffffffff1660e01b8152600401610266919061222f565b6102606040518083038186803b15801561027f57600080fd5b505afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b79190611fdd565b9050600081610220015190504261034a82856001600160a01b031663d8f897c3896040518263ffffffff1660e01b81526004016102f4919061222f565b60206040518083038186803b15801561030c57600080fd5b505afa158015610320573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610344919061218b565b9061167b565b111561035c5760009350505050610524565b60006103ee826103e8866001600160a01b031663d8f897c38a6040518263ffffffff1660e01b8152600401610391919061222f565b60206040518083038186803b1580156103a957600080fd5b505afa1580156103bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e1919061218b565b42906116d5565b90611732565b90506000846001600160a01b03166352f55eed886040518263ffffffff1660e01b815260040161041e919061222f565b60206040518083038186803b15801561043657600080fd5b505afa15801561044a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046e919061218b565b90508061048357600095505050505050610524565b61051c816103e884610516896001600160a01b031663c3c7b9e98d6040518263ffffffff1660e01b81526004016104ba919061222f565b60206040518083038186803b1580156104d257600080fd5b505afa1580156104e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050a919061218b565b6102408a015190611799565b90611799565b955050505050505b92915050565b61271081565b6000866001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561056b57600080fd5b505afa15801561057f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a39190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b1580156105dc57600080fd5b505afa1580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061491906120e3565b610120015161062457508261082d565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561065f57600080fd5b505afa158015610673573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106979190611c56565b6001600160a01b03166342e85182886040518263ffffffff1660e01b81526004016106c2919061222f565b60206040518083038186803b1580156106da57600080fd5b505afa1580156106ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610712919061218b565b90506000610720828861167b565b9050836107435781871161073d5761073882886116d5565b610740565b60005b90505b600061074f8a8a6117f2565b9050806107615786935050505061082d565b60008184116107795761077482856116d5565b610783565b61078384836116d5565b9050600082841161079d5761079883856116d5565b6107a7565b6107a784846116d5565b9050818110156107e95760006107c1846103e88b86611799565b90508981116107d9576107d48a826116d5565b6107dc565b60005b965050505050505061082d565b60006107fa60026103e8858561167b565b9050838111156108075750825b6000610817856103e88c85611799565b90506108238b8261167b565b9750505050505050505b9695505050505050565b6000806000886001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190611c56565b905060006108be828a8a8a8a611a5f565b805160408083015160c08401519151635c07eaab60e01b815293945060009384936001600160a01b03881693635c07eaab93610901938f93928f91600401612288565b604080518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109509190611c72565b91509150600061098261096b8e8e8e8e8e8a60000151611465565b610344878f8f8f8f8b600001518c606001516115b3565b9050821580156109955750818460200151105b156109d15787156109c15760405162461bcd60e51b81526004016109b890612326565b60405180910390fd5b600196509450610bbd9350505050565b6020840151836109ed5760208501516109ea90846116d5565b90505b81811015610a24578815610a135760405162461bcd60e51b81526004016109b8906123ed565b600197509550610bbd945050505050565b60008e6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610a5f57600080fd5b505afa158015610a73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a979190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b158015610ad057600080fd5b505afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0891906120e3565b9050610b228161010001518461167b90919063ffffffff16565b821015610b5a578915610b475760405162461bcd60e51b81526004016109b89061239f565b6001839850985050505050505050610bbd565b8551610b6890612710611799565b6040820151610b78908490611799565b1015610baf578915610b9c5760405162461bcd60e51b81526004016109b89061236a565b6002839850985050505050505050610bbd565b506000975090955050505050505b965096945050505050565b620f424081565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610c0b57600080fd5b505afa158015610c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c439190611c56565b9050600080876001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c8157600080fd5b505afa158015610c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb99190611c56565b6001600160a01b031663eab4d7a9846001600160a01b031663cb67e3b18a6040518263ffffffff1660e01b8152600401610cf3919061222f565b6102606040518083038186803b158015610d0c57600080fd5b505afa158015610d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d449190611fdd565b61010001518015610dd3575060405163cb67e3b160e01b81526001600160a01b0386169063cb67e3b190610d7c908b9060040161222f565b6102606040518083038186803b158015610d9557600080fd5b505afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190611fdd565b61010001515b6040518263ffffffff1660e01b8152600401610def91906122b8565b604080518083038186803b158015610e0657600080fd5b505afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e91906121a3565b915091506000610e5389898886866001610530565b90506000610e668a898987876000610530565b9050808211610e755780610e77565b815b9a9950505050505050505050565b600080856001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610ec157600080fd5b505afa158015610ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef99190611c56565b6001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401610f24919061222f565b6102606040518083038186803b158015610f3d57600080fd5b505afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190611fdd565b905061082d818585611b27565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015610fbe57600080fd5b505afa158015610fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff69190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561102f57600080fd5b505afa158015611043573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106791906120e3565b90506110808585858460a0015185606001516000610530565b9150505b9392505050565b600080846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156110c757600080fd5b505afa1580156110db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ff9190611c56565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561113857600080fd5b505afa15801561114c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117091906120e3565b90506110808585858460a0015185606001516001610530565b6000806000851160405180604001604052806002815260200161066760f31b815250906111c95760405162461bcd60e51b81526004016109b891906122d3565b506000886001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561120557600080fd5b505afa158015611219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123d9190611c56565b6001600160a01b03166376d697608987156040518363ffffffff1660e01b815260040161126b92919061226d565b60206040518083038186803b15801561128357600080fd5b505afa158015611297573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bb919061218b565b905060008187116112d5576112d082886116d5565b6112df565b6112df87836116d5565b905060006112f1886103e88b85611799565b9050600087156113045750878311611309565b508288115b60008c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561134457600080fd5b505afa158015611358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137c9190611c56565b6001600160a01b031663cb67e3b18d6040518263ffffffff1660e01b81526004016113a7919061222f565b6102606040518083038186803b1580156113c057600080fd5b505afa1580156113d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f89190611fdd565b9050600061141161140a838e8d611b27565b8a9061167b565b4211611421578160600151611424565b60005b905082801561144757506114388c82611799565b61144485612710611799565b11155b1561145157600093505b50909c919b50909950505050505050505050565b6000816114745750600061082d565b6000876001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156114af57600080fd5b505afa1580156114c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190611c56565b6001600160a01b031663cb67e3b1866040518263ffffffff1660e01b8152600401611512919061222f565b6102606040518083038186803b15801561152b57600080fd5b505afa15801561153f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115639190611fdd565b9050600061159a6127106103e8611593886115835785610200015161158a565b856101e001515b612710906116d5565b8790611799565b90506115a684826116d5565b9998505050505050505050565b6000826115c257506000611670565b600061164a838a6001600160a01b031663c65bc7b18a6040518263ffffffff1660e01b81526004016115f4919061222f565b60206040518083038186803b15801561160c57600080fd5b505afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611644919061218b565b906116d5565b90508061165b576000915050611670565b61166c620f42406103e88684611799565b9150505b979650505050505050565b600082820183811015611084576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008282111561172c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211611788576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161179157fe5b049392505050565b6000826117a857506000610524565b828202828482816117b557fe5b04146110845760405162461bcd60e51b81526004018080602001828103825260218152602001806124916021913960400191505060405180910390fd5b600080836001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561182e57600080fd5b505afa158015611842573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118669190611c56565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189e57600080fd5b505afa1580156118b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d6919061218b565b9050806118e7576000915050610524565b6000846001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561192257600080fd5b505afa158015611936573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195a9190611c56565b90506000816001600160a01b031663cb67e3b1866040518263ffffffff1660e01b815260040161198a919061222f565b6102606040518083038186803b1580156119a357600080fd5b505afa1580156119b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119db9190611fdd565b60400151905061082d826001600160a01b031663dc8f5fac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a1d57600080fd5b505afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a55919061218b565b6103e88386611799565b611a67611c09565b611a6f611c09565b60008060008060008b6001600160a01b0316634a3f088d8c8c8c8c6040518563ffffffff1660e01b8152600401611aa99493929190612243565b6101006040518083038186803b158015611ac257600080fd5b505afa158015611ad6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611afa91906121c6565b968d5250505060208a01929092526040890152606088015260c087015250939a9950505050505050505050565b6000821580611b3857506080840151155b15611b4557506000611084565b600082611b5757846101c00151611b5e565b846101a001515b905080611b715750506080830151611084565b8460a001518015611b8157508084105b80611b8b57508084145b15611b9c5750506080830151611084565b80841015611bc757611bbf816103e886886080015161179990919063ffffffff16565b915050611084565b611bbf6127106103e8836103e8611bfe611bf28b60c00151610516898d6116d590919063ffffffff16565b61034488612710611799565b60808b015190611799565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8051611c5181612482565b919050565b600060208284031215611c67578081fd5b81516110848161246a565b60008060408385031215611c84578081fd5b8251611c8f81612482565b6020939093015192949293505050565b60008060408385031215611cb1578182fd5b8235611cbc8161246a565b91506020830135611ccc8161246a565b809150509250929050565b60008060008060008060c08789031215611cef578182fd5b8635611cfa8161246a565b95506020870135611d0a8161246a565b94506040870135611d1a8161246a565b93506060870135611d2a8161246a565b92506080870135611d3a81612482565b915060a0870135611d4a81612482565b809150509295509295509295565b60008060008060008060c08789031215611d70578182fd5b8635611d7b8161246a565b95506020870135611d8b8161246a565b94506040870135611d9b8161246a565b93506060870135611dab8161246a565b92506080870135611dbb81612482565b8092505060a087013590509295509295509295565b60008060008060808587031215611de5578384fd5b8435611df08161246a565b93506020850135611e008161246a565b92506040850135611e108161246a565b9396929550929360600135925050565b600080600060608486031215611e34578081fd5b8335611e3f8161246a565b92506020840135611e4f8161246a565b929592945050506040919091013590565b60008060008060808587031215611e75578182fd5b8435611e808161246a565b93506020850135611e908161246a565b9250604085013591506060850135611ea781612482565b939692955090935050565b60008060008060008060c08789031215611eca578384fd5b8635611ed58161246a565b95506020870135611ee58161246a565b945060408701359350606087013592506080870135611dbb81612482565b60008060008060008060c08789031215611f1b578384fd5b8635611f268161246a565b95506020870135611f368161246a565b945060408701359350606087013592506080870135915060a0870135611d4a81612482565b600080600080600080600060e0888a031215611f75578485fd5b8735611f808161246a565b96506020880135611f908161246a565b95506040880135611fa08161246a565b94506060880135611fb08161246a565b93506080880135611fc081612482565b9699959850939692959460a0840135945060c09093013592915050565b6000610260808385031215611ff0578182fd5b611ff981612446565b905061200483611c46565b81526020830151602082015260408301516040820152606083015160608201526080830151608082015261203a60a08401611c46565b60a082015260c083015160c082015260e083015160e0820152610100612061818501611c46565b90820152610120612073848201611c46565b908201526101408381015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015261020080840151908201526102208084015190820152610240928301519281019290925250919050565b60006101608083850312156120f6578182fd5b6120ff81612446565b905061210a83611c46565b815261211860208401611c46565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612173818501611c46565b90820152610140928301519281019290925250919050565b60006020828403121561219c578081fd5b5051919050565b600080604083850312156121b5578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b0312156121e2578182fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c089015161221781612482565b8092505060e089015190509295985092959890939650565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039590951685526020850193909352604084019190915215156060830152608082015260a00190565b901515815260200190565b9115158252602082015260400190565b6000602080835283518082850152825b818110156122ff578581018301518582016040015282016122e3565b818111156123105783604083870101525b50601f01601f1916929092016040019392505050565b60208082526024908201527f5661756c745574696c733a206c6f737365732065786365656420636f6c6c6174604082015263195c985b60e21b606082015260800190565b6020808252818101527f5661756c745574696c733a206d61784c65766572616765206578636565646564604082015260600190565b6020808252602e908201527f5661756c745574696c733a206c69717569646174696f6e20666565732065786360408201526d1959590818dbdb1b185d195c985b60921b606082015260800190565b60208082526022908201527f5661756c745574696c733a20666565732065786365656420636f6c6c61746572604082015261185b60f21b606082015260800190565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561246257fe5b604052919050565b6001600160a01b038116811461247f57600080fd5b50565b801515811461247f57600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122050b0025f9b44f4e5dfa35dc924767108eaa667baa2870b32255d3d374c8c923564736f6c63430007060033