false
true
0

Contract Address Details

0x2286383aDB3D2a0e17846525DD2e8CCbF7793D7c

Contract Name
PhlpManager
Creator
0x64e7ff–1c04a3 at 0xe36282–d1403a
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
2,218 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26924090
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
PhlpManager




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




Optimization runs
200
EVM Version
istanbul




Verified at
2024-06-07T07:12:52.596744Z

Constructor Arguments

0x0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a270000000000000000000000000000000000000000000000000000000000000e10

Arg [0] (address) : 0x3cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1
Arg [1] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27
Arg [2] (uint256) : 3600

              

contracts/protocol/core/PhlpManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "../../dependencies/openzeppelin/contracts/Ownable.sol";
import "../../dependencies/openzeppelin/contracts/Address.sol";
import "../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../dependencies/openzeppelin/contracts/IERC20.sol";
import "../../dependencies/openzeppelin/contracts/SafeERC20.sol";
import "../../dependencies/openzeppelin/contracts/ReentrancyGuard.sol";
import "../../interfaces/IAddressesProvider.sol";
import "../../interfaces/IPhlpManager.sol";
import "../../interfaces/IUSDPH.sol";
import "../../interfaces/IPHLP.sol";
import "../../interfaces/IVault.sol";
import "../../interfaces/IVaultConfigurator.sol";
import "../../interfaces/IBasePositionManager.sol";
import "../../interfaces/IPhamePriceOracle.sol";
import "../../interfaces/IWETH.sol";
import "../../interfaces/IShortsTracker.sol";
import "../libraries/types/DataTypes.sol";

contract PhlpManager is IPhlpManager, ReentrancyGuard, Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using Address for address payable;

    uint256 public constant PRICE_PRECISION = 10 ** 30;
    uint256 public constant USDPH_DECIMALS = 18;
    uint256 public constant MAX_COOLDOWN_DURATION = 48 hours;

    IAddressesProvider public immutable addressesProvider;
    address public immutable weth;

    uint256 public override cooldownDuration;
    mapping(address => uint256) public override lastAddedAt;

    constructor(
        IAddressesProvider addressesProvider_,
        address _weth,
        uint256 _cooldownDuration
    ) Ownable() {
        require(
            address(addressesProvider_) != address(0),
            "PhlpManager: addressesProvider is zero address"
        );
        require(_weth != address(0), "PhlpManager: weth is zero address");
        addressesProvider = addressesProvider_;
        weth = _weth;
        cooldownDuration = _cooldownDuration;
    }

    function setCooldownDuration(uint256 _cooldownDuration) external onlyOwner {
        require(
            _cooldownDuration <= MAX_COOLDOWN_DURATION,
            "PhlpManager: invalid _cooldownDuration"
        );
        cooldownDuration = _cooldownDuration;
    }

    function addLiquidity(
        address _token,
        uint256 _amount,
        uint256 _minUsdph,
        uint256 _minPhlp
    ) external override nonReentrant returns (uint256) {
        require(_token != address(0), "PhlpManager: invalid _token");
        return _addLiquidity(msg.sender, _token, _amount, _minUsdph, _minPhlp);
    }

    function addLiquidityETH(
        uint256 _minUsdph,
        uint256 _minPhlp
    ) external payable override nonReentrant returns (uint256) {
        require(msg.value > 0, "PhlpManager: invalid msg.value");
        IWETH(weth).deposit{value: msg.value}();
        return
            _addLiquidity(
                msg.sender,
                address(0),
                msg.value,
                _minUsdph,
                _minPhlp
            );
    }

    function removeLiquidity(
        address _tokenOut,
        uint256 _phlpAmount,
        uint256 _minOut,
        address _receiver
    ) external override nonReentrant returns (uint256) {
        return
            _removeLiquidity(
                msg.sender,
                _tokenOut,
                _phlpAmount,
                _minOut,
                _receiver
            );
    }

    function removeLiquidityETH(
        uint256 _phlpAmount,
        uint256 _minOut,
        address payable _receiver
    ) external override nonReentrant returns (uint256) {
        uint256 amountOut = _removeLiquidity(
            msg.sender,
            weth,
            _phlpAmount,
            _minOut,
            address(this)
        );
        IWETH(weth).withdraw(amountOut);
        _receiver.sendValue(amountOut);
        return amountOut;
    }

    function getPrice(bool _maximise) external view override returns (uint256) {
        uint256 supply = IERC20(addressesProvider.getPhlp()).totalSupply();
        if (supply == 0) {
            return PRICE_PRECISION;
        }
        uint256 aum = getAum(_maximise);
        return aum.mul(10 ** 18).div(supply);
    }

    function getAums() public view override returns (uint256[] memory) {
        uint256[] memory amounts = new uint256[](2);
        amounts[0] = getAum(true);
        amounts[1] = getAum(false);
        return amounts;
    }

    function getAumInUsdph(bool maximise) public view returns (uint256) {
        uint256 aum = getAum(maximise);
        return aum.mul(10 ** USDPH_DECIMALS).div(PRICE_PRECISION);
    }

    function getAum(bool maximise) public view returns (uint256) {
        IVault vault = IVault(addressesProvider.getVault());
        IPhamePriceOracle oracle = IPhamePriceOracle(
            addressesProvider.getPriceOracle()
        );

        uint256 length = vault.allWhitelistedTokensLength();
        uint256 aum = 0;
        uint256 shortProfits = 0;

        for (uint256 i = 0; i < length; i++) {
            address token = vault.allWhitelistedTokens(i);
            DataTypes.TokenConfig memory tokenConfig = vault.getTokenConfig(
                token
            );

            uint256 price = oracle.getPrice(token, maximise);
            uint256 poolAmount = vault.poolAmounts(token);
            uint256 decimals = tokenConfig.decimals;

            if (tokenConfig.isStable) {
                aum = aum.add(poolAmount.mul(price).div(10 ** decimals));
            } else {
                // add global short profit / loss
                uint256 size = vault.globalShortSizes(token);
                if (size > 0) {
                    (uint256 delta, bool hasProfit) = getGlobalShortDelta(
                        token,
                        price,
                        size
                    );
                    if (!hasProfit) {
                        // add losses from shorts
                        aum = aum.add(delta);
                    } else {
                        shortProfits = shortProfits.add(delta);
                    }
                }

                aum = aum.add(vault.guaranteedUsd(token));

                uint256 reservedAmount = vault.reservedAmounts(token);
                aum = aum.add(
                    poolAmount.sub(reservedAmount).mul(price).div(
                        10 ** decimals
                    )
                );
            }
        }

        return aum = shortProfits > aum ? 0 : aum.sub(shortProfits);
    }

    function getGlobalShortDelta(
        address _token,
        uint256 _price,
        uint256 _size
    ) public view returns (uint256, bool) {
        uint256 averagePrice = IShortsTracker(
            addressesProvider.getShortsTracker()
        ).globalShortAveragePrices(_token);
        uint256 priceDelta = averagePrice > _price
            ? averagePrice.sub(_price)
            : _price.sub(averagePrice);
        uint256 delta = _size.mul(priceDelta).div(averagePrice);
        return (delta, averagePrice > _price);
    }

    function _addLiquidity(
        address _account,
        address _token,
        uint256 _amount,
        uint256 _minUsdph,
        uint256 _minPhlp
    ) private returns (uint256) {
        require(_amount > 0, "PhlpManager: invalid _amount");

        IVault vault = IVault(addressesProvider.getVault());
        address phlp = addressesProvider.getPhlp();

        // calculate aum before buyUSDPH
        uint256 aumInUsdph = getAumInUsdph(true);
        uint256 phlpSupply = IERC20(phlp).totalSupply();

        if (_token == address(0)) {
            IERC20(weth).transfer(address(vault), _amount);
            _token = weth;
        } else if (_account == address(this)) {
            IERC20(_token).safeTransfer(address(vault), _amount);
        } else {
            IERC20(_token).safeTransferFrom(_account, address(vault), _amount);
        }
        uint256 usdphAmount = _account == address(this)
            ? vault.buyUSDPHwithoutFee(_token)
            : vault.buyUSDPH(_token, address(this));
        require(
            usdphAmount >= _minUsdph,
            "PhlpManager: insufficient USDPH output"
        );

        uint256 mintAmount = aumInUsdph == 0
            ? usdphAmount
            : usdphAmount.mul(phlpSupply).div(aumInUsdph);
        require(
            mintAmount >= _minPhlp,
            "PhlpManager: insufficient PHLP output"
        );

        IPHLP(phlp).mint(_account, mintAmount);

        lastAddedAt[_account] = block.timestamp;

        emit AddLiquidity(
            _account,
            _token,
            _amount,
            aumInUsdph,
            phlpSupply,
            usdphAmount,
            mintAmount
        );

        return mintAmount;
    }

    function _removeLiquidity(
        address _account,
        address _tokenOut,
        uint256 _phlpAmount,
        uint256 _minOut,
        address _receiver
    ) private returns (uint256) {
        require(_phlpAmount > 0, "PhlpManager: invalid _phlpAmount");

        IVaultConfigurator vaultConfigurator = IVaultConfigurator(
            addressesProvider.getVaultConfigurator()
        );
        address phlp = addressesProvider.getPhlp();
        address usdph = addressesProvider.getUsdph();

        // calculate aum before sellUSDPH
        uint256 aumInUsdph = getAumInUsdph(false);
        uint256 phlpSupply = IERC20(phlp).totalSupply();

        uint256 usdphAmount = _phlpAmount.mul(aumInUsdph).div(phlpSupply);
        uint256 usdphBalance = IERC20(usdph).balanceOf(address(this));
        if (usdphAmount > usdphBalance) {
            IUSDPH(usdph).mint(address(this), usdphAmount.sub(usdphBalance));
        }

        IPHLP(phlp).burn(_account, _phlpAmount);

        IERC20(usdph).transfer(addressesProvider.getVault(), usdphAmount);
        uint256 stakingBps = IVault(addressesProvider.getVault())
            .getVaultConfig()
            .stakingBps;
        if (phlpSupply == _phlpAmount) {
            // when clearing out the vault
            // all fees should go to stakers (fee reserves) rather than the vault
            vaultConfigurator.setStakingBps(10000);
        }
        uint256 amountOut = IVault(addressesProvider.getVault()).sellUSDPH(
            _tokenOut,
            _receiver
        );
        if (phlpSupply == _phlpAmount) {
            vaultConfigurator.setStakingBps(stakingBps);
        }
        require(amountOut >= _minOut, "PhlpManager: insufficient output");

        emit RemoveLiquidity(
            _account,
            _tokenOut,
            _phlpAmount,
            aumInUsdph,
            phlpSupply,
            usdphAmount,
            amountOut
        );

        return amountOut;
    }

    receive() external payable {
        require(msg.sender == weth, "PhlpManager: invalid sender");
    }

    function convertFeesToLiquidity() external override nonReentrant {
        IVault vault = IVault(addressesProvider.getVault());
        IBasePositionManager positionManager = IBasePositionManager(
            addressesProvider.getPositionManager()
        );
        IBasePositionManager positionRouter = IBasePositionManager(
            addressesProvider.getPositionRouter()
        );

        // transfer fees to this contract and convert them to liquidity
        for (uint256 i = 0; i < vault.allWhitelistedTokensLength(); i++) {
            address tokenAddress = vault.allWhitelistedTokens(i);
            // collect fees
            vault.withdrawFees(tokenAddress, address(this));
            positionManager.withdrawFees(tokenAddress, address(this));
            positionRouter.withdrawFees(tokenAddress, address(this));
            // convert to liquidity
            IERC20 token = IERC20(tokenAddress);
            uint256 amount = token.balanceOf(address(this));
            if (amount > 0) {
                _addLiquidity(address(this), tokenAddress, amount, 0, 0);
            }
        }

        // transfer PHLP to treasury
        uint256 phlpBalance = IERC20(addressesProvider.getPhlp()).balanceOf(
            address(this)
        );
        if (phlpBalance > 0) {
            lastAddedAt[address(this)] = 0; // remove transfer constraints
            IERC20(addressesProvider.getPhlp()).transfer(
                addressesProvider.getFeeDistribution(),
                phlpBalance
            );
        }
    }
}
        

contracts/dependencies/openzeppelin/contracts/Address.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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 functionCall(target, data, "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"
        );
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{value: value}(
            data
        );
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
          

contracts/dependencies/openzeppelin/contracts/Context.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}
          

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/dependencies/openzeppelin/contracts/Ownable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

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

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

contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

contracts/dependencies/openzeppelin/contracts/SafeERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./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 SafeMath for uint256;
    using Address for address;

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

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
        );
    }

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

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

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(
            value,
            "SafeERC20: decreased allowance below zero"
        );
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(
                token.approve.selector,
                spender,
                newAllowance
            )
        );
    }

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

        bytes memory returndata = address(token).functionCall(
            data,
            "SafeERC20: low-level call failed"
        );
        if (returndata.length > 0) {
            // Return data is optional
            // solhint-disable-next-line max-line-length
            require(
                abi.decode(returndata, (bool)),
                "SafeERC20: ERC20 operation did not succeed"
            );
        }
    }
}
          

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/IBasePositionManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IBasePositionManager {
    event SetDepositFee(uint256 depositFee);
    event SetEthTransferGasLimit(uint256 ethTransferGasLimit);
    event SetMinTimeDelayPublic(uint256 minTimeDelayPublic);
    event SetIncreasePositionBufferBps(uint256 increasePositionBufferBps);
    event WithdrawFees(address token, address receiver, uint256 amount);

    function withdrawFees(address _token, address _receiver) external;
}
          

contracts/interfaces/IPHLP.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPHLP {
    function mint(address _account, uint256 _amount) external;

    function burn(address _account, uint256 _amount) external;
}
          

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/IPhlpManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPhlpManager {
    event AddLiquidity(
        address account,
        address token,
        uint256 amount,
        uint256 aumInUsdph,
        uint256 phlpSupply,
        uint256 usdphAmount,
        uint256 mintAmount
    );

    event RemoveLiquidity(
        address account,
        address token,
        uint256 phlpAmount,
        uint256 aumInUsdph,
        uint256 phlpSupply,
        uint256 usdphAmount,
        uint256 amountOut
    );

    function cooldownDuration() external view returns (uint256);

    function lastAddedAt(address _account) external view returns (uint256);

    function addLiquidity(
        address _token,
        uint256 _amount,
        uint256 _minUsdph,
        uint256 _minPhlp
    ) external returns (uint256);

    function addLiquidityETH(
        uint256 _minUsdph,
        uint256 _minPhlp
    ) external payable returns (uint256);

    function removeLiquidity(
        address _tokenOut,
        uint256 _phlpAmount,
        uint256 _minOut,
        address _receiver
    ) external returns (uint256);

    function removeLiquidityETH(
        uint256 _phlpAmount,
        uint256 _minOut,
        address payable _receiver
    ) external returns (uint256);

    function getAums() external view returns (uint256[] memory);

    function getPrice(bool _maximise) external view returns (uint256);

    function convertFeesToLiquidity() external;
}
          

contracts/interfaces/IShortsTracker.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IShortsTracker {
    function globalShortAveragePrices(
        address _token
    ) external view returns (uint256);

    function getNextGlobalShortData(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _nextPrice,
        uint256 _sizeDelta,
        bool _isIncrease
    ) external view returns (uint256, uint256);

    function updateGlobalShortData(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta,
        uint256 _markPrice,
        bool _isIncrease
    ) external;
}
          

contracts/interfaces/IUSDPH.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IUSDPH {
    function mint(address _account, uint256 _amount) external;

    function burn(address _account, uint256 _amount) 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/interfaces/IWETH.sol

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

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256) external;

    function approve(address guy, uint256 wad) external returns (bool);

    function transfer(address to, uint value) external returns (bool);

    function transferFrom(
        address src,
        address dst,
        uint256 wad
    ) external returns (bool);
}
          

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":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"addressesProvider_","internalType":"contract IAddressesProvider"},{"type":"address","name":"_weth","internalType":"address"},{"type":"uint256","name":"_cooldownDuration","internalType":"uint256"}]},{"type":"event","name":"AddLiquidity","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"aumInUsdph","internalType":"uint256","indexed":false},{"type":"uint256","name":"phlpSupply","internalType":"uint256","indexed":false},{"type":"uint256","name":"usdphAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"mintAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RemoveLiquidity","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"phlpAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"aumInUsdph","internalType":"uint256","indexed":false},{"type":"uint256","name":"phlpSupply","internalType":"uint256","indexed":false},{"type":"uint256","name":"usdphAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountOut","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_COOLDOWN_DURATION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PRICE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"USDPH_DECIMALS","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"addLiquidity","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint256","name":"_minUsdph","internalType":"uint256"},{"type":"uint256","name":"_minPhlp","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"addLiquidityETH","inputs":[{"type":"uint256","name":"_minUsdph","internalType":"uint256"},{"type":"uint256","name":"_minPhlp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAddressesProvider"}],"name":"addressesProvider","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"convertFeesToLiquidity","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cooldownDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAum","inputs":[{"type":"bool","name":"maximise","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAumInUsdph","inputs":[{"type":"bool","name":"maximise","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getAums","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"}],"name":"getGlobalShortDelta","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_price","internalType":"uint256"},{"type":"uint256","name":"_size","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPrice","inputs":[{"type":"bool","name":"_maximise","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastAddedAt","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"removeLiquidity","inputs":[{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"uint256","name":"_phlpAmount","internalType":"uint256"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"removeLiquidityETH","inputs":[{"type":"uint256","name":"_phlpAmount","internalType":"uint256"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"address","name":"_receiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCooldownDuration","inputs":[{"type":"uint256","name":"_cooldownDuration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"weth","inputs":[]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60c06040523480156200001157600080fd5b506040516200388738038062003887833981016040819052620000349162000116565b600160009081556200004562000112565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b038316620000c55760405162461bcd60e51b8152600401620000bc906200019e565b60405180910390fd5b6001600160a01b038216620000ee5760405162461bcd60e51b8152600401620000bc906200015d565b6001600160601b0319606093841b81166080529190921b1660a05260025562000205565b3390565b6000806000606084860312156200012b578283fd5b83516200013881620001ec565b60208501519093506200014b81620001ec565b80925050604084015190509250925092565b60208082526021908201527f50686c704d616e616765723a2077657468206973207a65726f206164647265736040820152607360f81b606082015260800190565b6020808252602e908201527f50686c704d616e616765723a2061646472657373657350726f7669646572206960408201526d73207a65726f206164647265737360901b606082015260800190565b6001600160a01b03811681146200020257600080fd5b50565b60805160601c60a05160601c6135e0620002a76000398061013e5280610a605280610aa15280610bc65280610dc552806127ad52806128395250806103f352806104885280610f05528061105752806110cb528061116052806111f5528061156d52806116a5528061173852806118495280611cb95280611d4e5280611de3528061206c528061217052806122e452806125df528061267452506135e06000f3fe60806040526004361061012e5760003560e01c80638da5cb5b116100ab578063a1acd3d51161006f578063a1acd3d514610334578063c72c4d1014610362578063dc21b44d14610377578063e245b5af1461038c578063ed0d1c04146103ac578063f2fde38b146103ce57610186565b80638da5cb5b146102b75780638fed0b2c146102cc5780638ffc80a1146102ec57806395082d25146102ff578063966be0751461031457610186565b806335269315116100f2578063352693151461022b5780633fc8cef3146102405780636bd3b5a314610262578063715018a6146102825780638b770e111461029757610186565b8063033914761461018b57806303563e67146101c1578063124e61c6146101d65780631e9049cf146101f65780631ece366a1461020b57610186565b3661018657336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101845760405162461bcd60e51b815260040161017b906132eb565b60405180910390fd5b005b600080fd5b34801561019757600080fd5b506101ab6101a6366004612f12565b6103ee565b6040516101b89190613265565b60405180910390f35b3480156101cd57600080fd5b506101ab610a06565b3480156101e257600080fd5b506101ab6101f1366004613149565b610a0b565b34801561020257600080fd5b506101ab610b29565b34801561021757600080fd5b506101ab610226366004612ed8565b610b30565b34801561023757600080fd5b506101ab610bbe565b34801561024c57600080fd5b50610255610bc4565b6040516101b89190613181565b34801561026e57600080fd5b506101ab61027d366004612f12565b610be8565b34801561028e57600080fd5b50610184610c20565b3480156102a357600080fd5b506101ab6102b2366004612e23565b610cde565b3480156102c357600080fd5b50610255610cf0565b3480156102d857600080fd5b506101ab6102e7366004612e8f565b610cff565b6101ab6102fa366004613128565b610d59565b34801561030b57600080fd5b506101ab610e51565b34801561032057600080fd5b5061018461032f3660046130f8565b610e62565b34801561034057600080fd5b5061035461034f366004612e5b565b610efe565b6040516101b8929190613485565b34801561036e57600080fd5b50610255611055565b34801561038357600080fd5b50610184611079565b34801561039857600080fd5b506101ab6103a7366004612f12565b611844565b3480156103b857600080fd5b506103c1611990565b6040516101b89190613221565b3480156103da57600080fd5b506101846103e9366004612e23565b6119ff565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561044a57600080fd5b505afa15801561045e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104829190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156104df57600080fd5b505afa1580156104f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105179190612e3f565b90506000826001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561055457600080fd5b505afa158015610568573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061058c9190613110565b905060008060005b838110156109df57604051630e468baf60e41b81526000906001600160a01b0388169063e468baf0906105cb908590600401613265565b60206040518083038186803b1580156105e357600080fd5b505afa1580156105f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061b9190612e3f565b90506000876001600160a01b031663cb67e3b1836040518263ffffffff1660e01b815260040161064b9190613181565b6102606040518083038186803b15801561066457600080fd5b505afa158015610678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069c9190612f4a565b90506000876001600160a01b03166376d69760848d6040518363ffffffff1660e01b81526004016106ce929190613206565b60206040518083038186803b1580156106e657600080fd5b505afa1580156106fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071e9190613110565b90506000896001600160a01b03166352f55eed856040518263ffffffff1660e01b815260040161074e9190613181565b60206040518083038186803b15801561076657600080fd5b505afa15801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190613110565b602084015161010085015191925090156107db576107d46107cd600a83900a6107c78587611b14565b90611b76565b8990611bdd565b97506109ce565b60405163114f1b5560e31b81526000906001600160a01b038d1690638a78daa89061080a908990600401613181565b60206040518083038186803b15801561082257600080fd5b505afa158015610836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085a9190613110565b9050801561089a57600080610870888785610efe565b915091508061088a576108838b83611bdd565b9a50610897565b6108948a83611bdd565b99505b50505b60405163783a2b6760e11b8152610921906001600160a01b038e169063f07456ce906108ca908a90600401613181565b60206040518083038186803b1580156108e257600080fd5b505afa1580156108f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091a9190613110565b8a90611bdd565b985060008c6001600160a01b031663c3c7b9e9886040518263ffffffff1660e01b81526004016109519190613181565b60206040518083038186803b15801561096957600080fd5b505afa15801561097d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a19190613110565b90506109c96109c2600a85900a6107c7886109bc8987611c37565b90611b14565b8b90611bdd565b995050505b505060019093019250610594915050565b508181116109f6576109f18282611c37565b6109f9565b60005b955050505050505b919050565b601281565b600060026000541415610a53576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b60026000908155610a87337f0000000000000000000000000000000000000000000000000000000000000000878730611c94565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90610ad6908490600401613265565b600060405180830381600087803b158015610af057600080fd5b505af1158015610b04573d6000803e3d6000fd5b50610b1c925050506001600160a01b038416826124d0565b6001600055949350505050565b6202a30081565b600060026000541415610b78576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b60026000556001600160a01b038516610ba35760405162461bcd60e51b815260040161017b90613419565b610bb033868686866125ba565b600160005595945050505050565b60025481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080610bf4836103ee565b9050610c196c0c9f2c9cd04674edea400000006107c783670de0b6b3a7640000611b14565b9392505050565b610c28612ae2565b6001600160a01b0316610c39610cf0565b6001600160a01b031614610c94576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60036020526000908152604090205481565b6001546001600160a01b031690565b600060026000541415610d47576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b6002600055610bb03386868686611c94565b600060026000541415610da1576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b600260005534610dc35760405162461bcd60e51b815260040161017b906132b4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1e57600080fd5b505af1158015610e32573d6000803e3d6000fd5b5050505050610e453360003486866125ba565b60016000559392505050565b6c0c9f2c9cd04674edea4000000081565b610e6a612ae2565b6001600160a01b0316610e7b610cf0565b6001600160a01b031614610ed6576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6202a300811115610ef95760405162461bcd60e51b815260040161017b90613359565b600255565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5c57600080fd5b505afa158015610f70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f949190612e3f565b6001600160a01b03166362749803876040518263ffffffff1660e01b8152600401610fbf9190613181565b60206040518083038186803b158015610fd757600080fd5b505afa158015610feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100f9190613110565b90506000858211611029576110248683611c37565b611033565b6110338287611c37565b90506000611045836107c78885611b14565b9450505084109050935093915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600260005414156110bf576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b600260008190555060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561112257600080fd5b505afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a9190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b757600080fd5b505afa1580156111cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ef9190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634bd9a9aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561124c57600080fd5b505afa158015611260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112849190612e3f565b905060005b836001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b1580156112c257600080fd5b505afa1580156112d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fa9190613110565b81101561156857604051630e468baf60e41b81526000906001600160a01b0386169063e468baf090611330908590600401613265565b60206040518083038186803b15801561134857600080fd5b505afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113809190612e3f565b604051631e4aaa4f60e31b81529091506001600160a01b0386169063f2555278906113b190849030906004016131ae565b602060405180830381600087803b1580156113cb57600080fd5b505af11580156113df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114039190613110565b50604051631e4aaa4f60e31b81526001600160a01b0385169063f25552789061143290849030906004016131ae565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b5050604051631e4aaa4f60e31b81526001600160a01b038616925063f2555278915061149290849030906004016131ae565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b50506040516370a0823160e01b8152839250600091506001600160a01b038316906370a08231906114f5903090600401613181565b60206040518083038186803b15801561150d57600080fd5b505afa158015611521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190613110565b9050801561155d5761155b3084836000806125ba565b505b505050600101611289565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115c457600080fd5b505afa1580156115d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fc9190612e3f565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116279190613181565b60206040518083038186803b15801561163f57600080fd5b505afa158015611653573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116779190613110565b905080156118395730600090815260036020908152604080832092909255815163fd591dcd60e01b815291517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169263fd591dcd926004808301939192829003018186803b1580156116f057600080fd5b505afa158015611704573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117289190612e3f565b6001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663752f77f16040518163ffffffff1660e01b815260040160206040518083038186803b15801561178f57600080fd5b505afa1580156117a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c79190612e3f565b836040518363ffffffff1660e01b81526004016117e5929190613195565b602060405180830381600087803b1580156117ff57600080fd5b505af1158015611813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118379190612f2e565b505b505060016000555050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d89190612e3f565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561191057600080fd5b505afa158015611924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119489190613110565b905080611965576c0c9f2c9cd04674edea40000000915050610a01565b6000611970846103ee565b9050611988826107c783670de0b6b3a7640000611b14565b949350505050565b604080516002808252606080830184529260009291906020830190803683370190505090506119bf60016103ee565b816000815181106119cc57fe5b6020026020010181815250506119e260006103ee565b816001815181106119ef57fe5b6020908102919091010152905090565b611a07612ae2565b6001600160a01b0316611a18610cf0565b6001600160a01b031614611a73576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611ab85760405162461bcd60e51b81526004018080602001828103825260268152602001806135006026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600082611b2357506000611b70565b82820282848281611b3057fe5b0414611b6d5760405162461bcd60e51b81526004018080602001828103825260218152602001806135606021913960400191505060405180910390fd5b90505b92915050565b6000808211611bcc576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611bd557fe5b049392505050565b600082820183811015611b6d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115611c8e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808411611cb55760405162461bcd60e51b815260040161017b90613450565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1057600080fd5b505afa158015611d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d489190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da557600080fd5b505afa158015611db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddd9190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3a57600080fd5b505afa158015611e4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e729190612e3f565b90506000611e806000610be8565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef59190613110565b90506000611f07826107c78c86611b14565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611f379190613181565b60206040518083038186803b158015611f4f57600080fd5b505afa158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f879190613110565b905080821115611ffb576001600160a01b0385166340c10f1930611fab8585611c37565b6040518363ffffffff1660e01b8152600401611fc8929190613195565b600060405180830381600087803b158015611fe257600080fd5b505af1158015611ff6573d6000803e3d6000fd5b505050505b856001600160a01b0316639dc29fac8e8d6040518363ffffffff1660e01b8152600401612029929190613195565b600060405180830381600087803b15801561204357600080fd5b505af1158015612057573d6000803e3d6000fd5b50505050846001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156120c357600080fd5b505afa1580156120d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fb9190612e3f565b846040518363ffffffff1660e01b8152600401612119929190613195565b602060405180830381600087803b15801561213357600080fd5b505af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b9190612f2e565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156121c757600080fd5b505afa1580156121db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ff9190612e3f565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561223857600080fd5b505afa15801561224c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122709190613050565b610140015190508b8414156122e057604051632413866560e01b81526001600160a01b038916906324138665906122ad9061271090600401613265565b600060405180830381600087803b1580156122c757600080fd5b505af11580156122db573d6000803e3d6000fd5b505050505b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561233b57600080fd5b505afa15801561234f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123739190612e3f565b6001600160a01b0316635bae42638f8d6040518363ffffffff1660e01b81526004016123a09291906131ae565b602060405180830381600087803b1580156123ba57600080fd5b505af11580156123ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f29190613110565b90508c85141561245b57604051632413866560e01b81526001600160a01b038a1690632413866590612428908590600401613265565b600060405180830381600087803b15801561244257600080fd5b505af1158015612456573d6000803e3d6000fd5b505050505b8b81101561247b5760405162461bcd60e51b815260040161017b9061339f565b7f87b9679bb9a4944bafa98c267e7cd4a00ab29fed48afdefae25f0fca5da279408f8f8f898989876040516124b697969594939291906131c8565b60405180910390a19e9d5050505050505050505050505050565b80471015612525576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612570576040519150601f19603f3d011682016040523d82523d6000602084013e612575565b606091505b50509050806125b55760405162461bcd60e51b815260040180806020018281038252603a815260200180613526603a913960400191505060405180910390fd5b505050565b60008084116125db5760405162461bcd60e51b815260040161017b90613322565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561263657600080fd5b505afa15801561264a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266e9190612e3f565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126cb57600080fd5b505afa1580156126df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127039190612e3f565b905060006127116001610be8565b90506000826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561274e57600080fd5b505afa158015612762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127869190613110565b90506001600160a01b03891661285f5760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906127e49087908c90600401613195565b602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190612f2e565b507f0000000000000000000000000000000000000000000000000000000000000000985061289e565b6001600160a01b038a16301415612889576128846001600160a01b038a16858a612ae6565b61289e565b61289e6001600160a01b038a168b868b612b38565b60006001600160a01b038b16301461293557604051635da69ed760e01b81526001600160a01b03861690635da69ed7906128de908d9030906004016131ae565b602060405180830381600087803b1580156128f857600080fd5b505af115801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190613110565b6129b3565b60405163080d568b60e21b81526001600160a01b038616906320355a2c90612961908d90600401613181565b602060405180830381600087803b15801561297b57600080fd5b505af115801561298f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b39190613110565b9050878110156129d55760405162461bcd60e51b815260040161017b9061326e565b600083156129f0576129eb846107c78486611b14565b6129f2565b815b905087811015612a145760405162461bcd60e51b815260040161017b906133d4565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990612a42908f908590600401613195565b600060405180830381600087803b158015612a5c57600080fd5b505af1158015612a70573d6000803e3d6000fd5b5050506001600160a01b038d1660009081526003602052604090819020429055517f38dc38b96482be64113daffd8d464ebda93e856b70ccfc605e69ccf892ab981e9150612acb908e908e908e9089908990899089906131c8565b60405180910390a19b9a5050505050505050505050565b3390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526125b5908490612b98565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612b92908590612b98565b50505050565b6000612bed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612c499092919063ffffffff16565b8051909150156125b557808060200190516020811015612c0c57600080fd5b50516125b55760405162461bcd60e51b815260040180806020018281038252602a815260200180613581602a913960400191505060405180910390fd5b6060611988848460008585612c5d85612d6e565b612cae576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612cec5780518252601f199092019160209182019101612ccd565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612d4e576040519150601f19603f3d011682016040523d82523d6000602084013e612d53565b606091505b5091509150612d63828286612d74565b979650505050505050565b3b151590565b60608315612d83575081610c19565b825115612d935782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612ddd578181015183820152602001612dc5565b50505050905090810190601f168015612e0a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8051610a01816134d1565b600060208284031215612e34578081fd5b8135611b6d816134b9565b600060208284031215612e50578081fd5b8151611b6d816134b9565b600080600060608486031215612e6f578182fd5b8335612e7a816134b9565b95602085013595506040909401359392505050565b60008060008060808587031215612ea4578081fd5b8435612eaf816134b9565b935060208501359250604085013591506060850135612ecd816134b9565b939692955090935050565b60008060008060808587031215612eed578384fd5b8435612ef8816134b9565b966020860135965060408601359560600135945092505050565b600060208284031215612f23578081fd5b8135611b6d816134d1565b600060208284031215612f3f578081fd5b8151611b6d816134d1565b6000610260808385031215612f5d578182fd5b612f6681613495565b9050612f7183612e18565b815260208301516020820152604083015160408201526060830151606082015260808301516080820152612fa760a08401612e18565b60a082015260c083015160c082015260e083015160e0820152610100612fce818501612e18565b90820152610120612fe0848201612e18565b908201526101408381015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015261020080840151908201526102208084015190820152610240928301519281019290925250919050565b6000610160808385031215613063578182fd5b61306c81613495565b905061307783612e18565b815261308560208401612e18565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206130e0818501612e18565b90820152610140928301519281019290925250919050565b600060208284031215613109578081fd5b5035919050565b600060208284031215613121578081fd5b5051919050565b6000806040838503121561313a578182fd5b50508035926020909101359150565b60008060006060848603121561315d578081fd5b83359250602084013591506040840135613176816134b9565b809150509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156132595783518352928401929184019160010161323d565b50909695505050505050565b90815260200190565b60208082526026908201527f50686c704d616e616765723a20696e73756666696369656e74205553445048206040820152651bdd5d1c1d5d60d21b606082015260800190565b6020808252601e908201527f50686c704d616e616765723a20696e76616c6964206d73672e76616c75650000604082015260600190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c69642073656e6465720000000000604082015260600190565b6020808252601c908201527f50686c704d616e616765723a20696e76616c6964205f616d6f756e7400000000604082015260600190565b60208082526026908201527f50686c704d616e616765723a20696e76616c6964205f636f6f6c646f776e44756040820152653930ba34b7b760d11b606082015260800190565b6020808252818101527f50686c704d616e616765723a20696e73756666696369656e74206f7574707574604082015260600190565b60208082526025908201527f50686c704d616e616765723a20696e73756666696369656e742050484c50206f6040820152641d5d1c1d5d60da1b606082015260800190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c6964205f746f6b656e0000000000604082015260600190565b6020808252818101527f50686c704d616e616765723a20696e76616c6964205f70686c70416d6f756e74604082015260600190565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156134b157fe5b604052919050565b6001600160a01b03811681146134ce57600080fd5b50565b80151581146134ce57600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212208703bc414c2b9927acb1862b430585ff560854d6050af9dfd4d119eb8f14573564736f6c634300070600330000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a270000000000000000000000000000000000000000000000000000000000000e10

Deployed ByteCode

0x60806040526004361061012e5760003560e01c80638da5cb5b116100ab578063a1acd3d51161006f578063a1acd3d514610334578063c72c4d1014610362578063dc21b44d14610377578063e245b5af1461038c578063ed0d1c04146103ac578063f2fde38b146103ce57610186565b80638da5cb5b146102b75780638fed0b2c146102cc5780638ffc80a1146102ec57806395082d25146102ff578063966be0751461031457610186565b806335269315116100f2578063352693151461022b5780633fc8cef3146102405780636bd3b5a314610262578063715018a6146102825780638b770e111461029757610186565b8063033914761461018b57806303563e67146101c1578063124e61c6146101d65780631e9049cf146101f65780631ece366a1461020b57610186565b3661018657336001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2716146101845760405162461bcd60e51b815260040161017b906132eb565b60405180910390fd5b005b600080fd5b34801561019757600080fd5b506101ab6101a6366004612f12565b6103ee565b6040516101b89190613265565b60405180910390f35b3480156101cd57600080fd5b506101ab610a06565b3480156101e257600080fd5b506101ab6101f1366004613149565b610a0b565b34801561020257600080fd5b506101ab610b29565b34801561021757600080fd5b506101ab610226366004612ed8565b610b30565b34801561023757600080fd5b506101ab610bbe565b34801561024c57600080fd5b50610255610bc4565b6040516101b89190613181565b34801561026e57600080fd5b506101ab61027d366004612f12565b610be8565b34801561028e57600080fd5b50610184610c20565b3480156102a357600080fd5b506101ab6102b2366004612e23565b610cde565b3480156102c357600080fd5b50610255610cf0565b3480156102d857600080fd5b506101ab6102e7366004612e8f565b610cff565b6101ab6102fa366004613128565b610d59565b34801561030b57600080fd5b506101ab610e51565b34801561032057600080fd5b5061018461032f3660046130f8565b610e62565b34801561034057600080fd5b5061035461034f366004612e5b565b610efe565b6040516101b8929190613485565b34801561036e57600080fd5b50610255611055565b34801561038357600080fd5b50610184611079565b34801561039857600080fd5b506101ab6103a7366004612f12565b611844565b3480156103b857600080fd5b506103c1611990565b6040516101b89190613221565b3480156103da57600080fd5b506101846103e9366004612e23565b6119ff565b6000807f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561044a57600080fd5b505afa15801561045e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104829190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156104df57600080fd5b505afa1580156104f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105179190612e3f565b90506000826001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561055457600080fd5b505afa158015610568573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061058c9190613110565b905060008060005b838110156109df57604051630e468baf60e41b81526000906001600160a01b0388169063e468baf0906105cb908590600401613265565b60206040518083038186803b1580156105e357600080fd5b505afa1580156105f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061b9190612e3f565b90506000876001600160a01b031663cb67e3b1836040518263ffffffff1660e01b815260040161064b9190613181565b6102606040518083038186803b15801561066457600080fd5b505afa158015610678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069c9190612f4a565b90506000876001600160a01b03166376d69760848d6040518363ffffffff1660e01b81526004016106ce929190613206565b60206040518083038186803b1580156106e657600080fd5b505afa1580156106fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071e9190613110565b90506000896001600160a01b03166352f55eed856040518263ffffffff1660e01b815260040161074e9190613181565b60206040518083038186803b15801561076657600080fd5b505afa15801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190613110565b602084015161010085015191925090156107db576107d46107cd600a83900a6107c78587611b14565b90611b76565b8990611bdd565b97506109ce565b60405163114f1b5560e31b81526000906001600160a01b038d1690638a78daa89061080a908990600401613181565b60206040518083038186803b15801561082257600080fd5b505afa158015610836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085a9190613110565b9050801561089a57600080610870888785610efe565b915091508061088a576108838b83611bdd565b9a50610897565b6108948a83611bdd565b99505b50505b60405163783a2b6760e11b8152610921906001600160a01b038e169063f07456ce906108ca908a90600401613181565b60206040518083038186803b1580156108e257600080fd5b505afa1580156108f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091a9190613110565b8a90611bdd565b985060008c6001600160a01b031663c3c7b9e9886040518263ffffffff1660e01b81526004016109519190613181565b60206040518083038186803b15801561096957600080fd5b505afa15801561097d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a19190613110565b90506109c96109c2600a85900a6107c7886109bc8987611c37565b90611b14565b8b90611bdd565b995050505b505060019093019250610594915050565b508181116109f6576109f18282611c37565b6109f9565b60005b955050505050505b919050565b601281565b600060026000541415610a53576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b60026000908155610a87337f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27878730611c94565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a271690632e1a7d4d90610ad6908490600401613265565b600060405180830381600087803b158015610af057600080fd5b505af1158015610b04573d6000803e3d6000fd5b50610b1c925050506001600160a01b038416826124d0565b6001600055949350505050565b6202a30081565b600060026000541415610b78576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b60026000556001600160a01b038516610ba35760405162461bcd60e51b815260040161017b90613419565b610bb033868686866125ba565b600160005595945050505050565b60025481565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b600080610bf4836103ee565b9050610c196c0c9f2c9cd04674edea400000006107c783670de0b6b3a7640000611b14565b9392505050565b610c28612ae2565b6001600160a01b0316610c39610cf0565b6001600160a01b031614610c94576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60036020526000908152604090205481565b6001546001600160a01b031690565b600060026000541415610d47576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b6002600055610bb03386868686611c94565b600060026000541415610da1576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b600260005534610dc35760405162461bcd60e51b815260040161017b906132b4565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a276001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1e57600080fd5b505af1158015610e32573d6000803e3d6000fd5b5050505050610e453360003486866125ba565b60016000559392505050565b6c0c9f2c9cd04674edea4000000081565b610e6a612ae2565b6001600160a01b0316610e7b610cf0565b6001600160a01b031614610ed6576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6202a300811115610ef95760405162461bcd60e51b815260040161017b90613359565b600255565b60008060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b158015610f5c57600080fd5b505afa158015610f70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f949190612e3f565b6001600160a01b03166362749803876040518263ffffffff1660e01b8152600401610fbf9190613181565b60206040518083038186803b158015610fd757600080fd5b505afa158015610feb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100f9190613110565b90506000858211611029576110248683611c37565b611033565b6110338287611c37565b90506000611045836107c78885611b14565b9450505084109050935093915050565b7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f181565b600260005414156110bf576040805162461bcd60e51b815260206004820152601f60248201526000805160206134e0833981519152604482015290519081900360640190fd5b600260008190555060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561112257600080fd5b505afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a9190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111b757600080fd5b505afa1580156111cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ef9190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316634bd9a9aa6040518163ffffffff1660e01b815260040160206040518083038186803b15801561124c57600080fd5b505afa158015611260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112849190612e3f565b905060005b836001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b1580156112c257600080fd5b505afa1580156112d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fa9190613110565b81101561156857604051630e468baf60e41b81526000906001600160a01b0386169063e468baf090611330908590600401613265565b60206040518083038186803b15801561134857600080fd5b505afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113809190612e3f565b604051631e4aaa4f60e31b81529091506001600160a01b0386169063f2555278906113b190849030906004016131ae565b602060405180830381600087803b1580156113cb57600080fd5b505af11580156113df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114039190613110565b50604051631e4aaa4f60e31b81526001600160a01b0385169063f25552789061143290849030906004016131ae565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b5050604051631e4aaa4f60e31b81526001600160a01b038616925063f2555278915061149290849030906004016131ae565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b50506040516370a0823160e01b8152839250600091506001600160a01b038316906370a08231906114f5903090600401613181565b60206040518083038186803b15801561150d57600080fd5b505afa158015611521573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115459190613110565b9050801561155d5761155b3084836000806125ba565b505b505050600101611289565b5060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115c457600080fd5b505afa1580156115d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fc9190612e3f565b6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116279190613181565b60206040518083038186803b15801561163f57600080fd5b505afa158015611653573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116779190613110565b905080156118395730600090815260036020908152604080832092909255815163fd591dcd60e01b815291517f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b03169263fd591dcd926004808301939192829003018186803b1580156116f057600080fd5b505afa158015611704573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117289190612e3f565b6001600160a01b031663a9059cbb7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663752f77f16040518163ffffffff1660e01b815260040160206040518083038186803b15801561178f57600080fd5b505afa1580156117a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c79190612e3f565b836040518363ffffffff1660e01b81526004016117e5929190613195565b602060405180830381600087803b1580156117ff57600080fd5b505af1158015611813573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118379190612f2e565b505b505060016000555050565b6000807f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d89190612e3f565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561191057600080fd5b505afa158015611924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119489190613110565b905080611965576c0c9f2c9cd04674edea40000000915050610a01565b6000611970846103ee565b9050611988826107c783670de0b6b3a7640000611b14565b949350505050565b604080516002808252606080830184529260009291906020830190803683370190505090506119bf60016103ee565b816000815181106119cc57fe5b6020026020010181815250506119e260006103ee565b816001815181106119ef57fe5b6020908102919091010152905090565b611a07612ae2565b6001600160a01b0316611a18610cf0565b6001600160a01b031614611a73576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611ab85760405162461bcd60e51b81526004018080602001828103825260268152602001806135006026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600082611b2357506000611b70565b82820282848281611b3057fe5b0414611b6d5760405162461bcd60e51b81526004018080602001828103825260218152602001806135606021913960400191505060405180910390fd5b90505b92915050565b6000808211611bcc576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611bd557fe5b049392505050565b600082820183811015611b6d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115611c8e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808411611cb55760405162461bcd60e51b815260040161017b90613450565b60007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1057600080fd5b505afa158015611d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d489190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611da557600080fd5b505afa158015611db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddd9190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3a57600080fd5b505afa158015611e4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e729190612e3f565b90506000611e806000610be8565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef59190613110565b90506000611f07826107c78c86611b14565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611f379190613181565b60206040518083038186803b158015611f4f57600080fd5b505afa158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f879190613110565b905080821115611ffb576001600160a01b0385166340c10f1930611fab8585611c37565b6040518363ffffffff1660e01b8152600401611fc8929190613195565b600060405180830381600087803b158015611fe257600080fd5b505af1158015611ff6573d6000803e3d6000fd5b505050505b856001600160a01b0316639dc29fac8e8d6040518363ffffffff1660e01b8152600401612029929190613195565b600060405180830381600087803b15801561204357600080fd5b505af1158015612057573d6000803e3d6000fd5b50505050846001600160a01b031663a9059cbb7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156120c357600080fd5b505afa1580156120d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fb9190612e3f565b846040518363ffffffff1660e01b8152600401612119929190613195565b602060405180830381600087803b15801561213357600080fd5b505af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b9190612f2e565b5060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b1580156121c757600080fd5b505afa1580156121db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ff9190612e3f565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016101606040518083038186803b15801561223857600080fd5b505afa15801561224c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122709190613050565b610140015190508b8414156122e057604051632413866560e01b81526001600160a01b038916906324138665906122ad9061271090600401613265565b600060405180830381600087803b1580156122c757600080fd5b505af11580156122db573d6000803e3d6000fd5b505050505b60007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561233b57600080fd5b505afa15801561234f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123739190612e3f565b6001600160a01b0316635bae42638f8d6040518363ffffffff1660e01b81526004016123a09291906131ae565b602060405180830381600087803b1580156123ba57600080fd5b505af11580156123ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f29190613110565b90508c85141561245b57604051632413866560e01b81526001600160a01b038a1690632413866590612428908590600401613265565b600060405180830381600087803b15801561244257600080fd5b505af1158015612456573d6000803e3d6000fd5b505050505b8b81101561247b5760405162461bcd60e51b815260040161017b9061339f565b7f87b9679bb9a4944bafa98c267e7cd4a00ab29fed48afdefae25f0fca5da279408f8f8f898989876040516124b697969594939291906131c8565b60405180910390a19e9d5050505050505050505050505050565b80471015612525576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612570576040519150601f19603f3d011682016040523d82523d6000602084013e612575565b606091505b50509050806125b55760405162461bcd60e51b815260040180806020018281038252603a815260200180613526603a913960400191505060405180910390fd5b505050565b60008084116125db5760405162461bcd60e51b815260040161017b90613322565b60007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561263657600080fd5b505afa15801561264a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266e9190612e3f565b905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156126cb57600080fd5b505afa1580156126df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127039190612e3f565b905060006127116001610be8565b90506000826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561274e57600080fd5b505afa158015612762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127869190613110565b90506001600160a01b03891661285f5760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27169063a9059cbb906127e49087908c90600401613195565b602060405180830381600087803b1580156127fe57600080fd5b505af1158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190612f2e565b507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27985061289e565b6001600160a01b038a16301415612889576128846001600160a01b038a16858a612ae6565b61289e565b61289e6001600160a01b038a168b868b612b38565b60006001600160a01b038b16301461293557604051635da69ed760e01b81526001600160a01b03861690635da69ed7906128de908d9030906004016131ae565b602060405180830381600087803b1580156128f857600080fd5b505af115801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190613110565b6129b3565b60405163080d568b60e21b81526001600160a01b038616906320355a2c90612961908d90600401613181565b602060405180830381600087803b15801561297b57600080fd5b505af115801561298f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129b39190613110565b9050878110156129d55760405162461bcd60e51b815260040161017b9061326e565b600083156129f0576129eb846107c78486611b14565b6129f2565b815b905087811015612a145760405162461bcd60e51b815260040161017b906133d4565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990612a42908f908590600401613195565b600060405180830381600087803b158015612a5c57600080fd5b505af1158015612a70573d6000803e3d6000fd5b5050506001600160a01b038d1660009081526003602052604090819020429055517f38dc38b96482be64113daffd8d464ebda93e856b70ccfc605e69ccf892ab981e9150612acb908e908e908e9089908990899089906131c8565b60405180910390a19b9a5050505050505050505050565b3390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526125b5908490612b98565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612b92908590612b98565b50505050565b6000612bed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612c499092919063ffffffff16565b8051909150156125b557808060200190516020811015612c0c57600080fd5b50516125b55760405162461bcd60e51b815260040180806020018281038252602a815260200180613581602a913960400191505060405180910390fd5b6060611988848460008585612c5d85612d6e565b612cae576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612cec5780518252601f199092019160209182019101612ccd565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612d4e576040519150601f19603f3d011682016040523d82523d6000602084013e612d53565b606091505b5091509150612d63828286612d74565b979650505050505050565b3b151590565b60608315612d83575081610c19565b825115612d935782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612ddd578181015183820152602001612dc5565b50505050905090810190601f168015612e0a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8051610a01816134d1565b600060208284031215612e34578081fd5b8135611b6d816134b9565b600060208284031215612e50578081fd5b8151611b6d816134b9565b600080600060608486031215612e6f578182fd5b8335612e7a816134b9565b95602085013595506040909401359392505050565b60008060008060808587031215612ea4578081fd5b8435612eaf816134b9565b935060208501359250604085013591506060850135612ecd816134b9565b939692955090935050565b60008060008060808587031215612eed578384fd5b8435612ef8816134b9565b966020860135965060408601359560600135945092505050565b600060208284031215612f23578081fd5b8135611b6d816134d1565b600060208284031215612f3f578081fd5b8151611b6d816134d1565b6000610260808385031215612f5d578182fd5b612f6681613495565b9050612f7183612e18565b815260208301516020820152604083015160408201526060830151606082015260808301516080820152612fa760a08401612e18565b60a082015260c083015160c082015260e083015160e0820152610100612fce818501612e18565b90820152610120612fe0848201612e18565b908201526101408381015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015261020080840151908201526102208084015190820152610240928301519281019290925250919050565b6000610160808385031215613063578182fd5b61306c81613495565b905061307783612e18565b815261308560208401612e18565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206130e0818501612e18565b90820152610140928301519281019290925250919050565b600060208284031215613109578081fd5b5035919050565b600060208284031215613121578081fd5b5051919050565b6000806040838503121561313a578182fd5b50508035926020909101359150565b60008060006060848603121561315d578081fd5b83359250602084013591506040840135613176816134b9565b809150509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6020808252825182820181905260009190848201906040850190845b818110156132595783518352928401929184019160010161323d565b50909695505050505050565b90815260200190565b60208082526026908201527f50686c704d616e616765723a20696e73756666696369656e74205553445048206040820152651bdd5d1c1d5d60d21b606082015260800190565b6020808252601e908201527f50686c704d616e616765723a20696e76616c6964206d73672e76616c75650000604082015260600190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c69642073656e6465720000000000604082015260600190565b6020808252601c908201527f50686c704d616e616765723a20696e76616c6964205f616d6f756e7400000000604082015260600190565b60208082526026908201527f50686c704d616e616765723a20696e76616c6964205f636f6f6c646f776e44756040820152653930ba34b7b760d11b606082015260800190565b6020808252818101527f50686c704d616e616765723a20696e73756666696369656e74206f7574707574604082015260600190565b60208082526025908201527f50686c704d616e616765723a20696e73756666696369656e742050484c50206f6040820152641d5d1c1d5d60da1b606082015260800190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c6964205f746f6b656e0000000000604082015260600190565b6020808252818101527f50686c704d616e616765723a20696e76616c6964205f70686c70416d6f756e74604082015260600190565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156134b157fe5b604052919050565b6001600160a01b03811681146134ce57600080fd5b50565b80151581146134ce57600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212208703bc414c2b9927acb1862b430585ff560854d6050af9dfd4d119eb8f14573564736f6c63430007060033