false
true
0

Contract Address Details

0x268976b5B57A75A0a3e25Bf1d567BB72418b2925

Contract Name
PhlpManager
Creator
0x64e7ff–1c04a3 at 0x8b59ed–1a8aed
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
9,429 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26091932
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
2023-09-15T17:46:55.370777Z

Constructor Arguments

0x000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000000000000000000000000000000000000000038400000000000000000000000042a0744fbc3d5d103856d61d14d45871ef533379

Arg [0] (address) : 0xb29ea150c870ea830d9890d94f326cb1b273ce8c
Arg [1] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27
Arg [2] (uint256) : 900
Arg [3] (address) : 0x42a0744fbc3d5d103856d61d14d45871ef533379

              

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 "../../dependencies/governance/TreasuryOwnable.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,
    TreasuryOwnable
{
    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,
        address treasury
    ) Ownable() TreasuryOwnable(treasury) {
        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
        onlyTreasury
    {
        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(
                msg.sender,
                phlpBalance
            );
        }
    }
}
        

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 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/dependencies/governance/TreasuryOwnable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../openzeppelin/contracts/Context.sol";

abstract contract TreasuryOwnable is Context {
    address private _treasury;

    event TreasuryTransferred(
        address indexed previousTreasury,
        address indexed newTreasury
    );

    /**
     * @dev Initializes the contract setting the given account (`treasury_`) as the initial treasury.
     */
    constructor(address treasury_) {
        _treasury = treasury_;
        emit TreasuryTransferred(address(0), treasury_);
    }

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

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

    /**
     * @dev Transfers treasury of the contract to a new account (`newTreasury`).
     * Can only be called by the current treasury.
     */
    function transferTreasury(
        address newTreasury
    ) external virtual onlyTreasury {
        require(
            newTreasury != address(0),
            "TreasuryOwnable: new treasury is the zero address"
        );
        _transferTreasury(newTreasury);
    }

    function _transferTreasury(address newTreasury) internal virtual {
        emit TreasuryTransferred(_treasury, newTreasury);
        _treasury = newTreasury;
    }
}
          

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

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);

    event SetMaxGlobalSizes(
        address[] tokens,
        uint256[] longSizes,
        uint256[] shortSizes
    );

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

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

    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/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 marginFeeBps;
        uint256 liquidationFeeUsd;
        uint256 minProfitTime;
        bool hasDynamicFees;
        // staking
        uint256 stakingBps;
        // funding rate
        uint256 fundingInterval;
        uint256 fundingRateFactor;
        uint256 stableFundingRateFactor;
    }

    struct TokenConfig {
        // should always be true if token exists
        bool isWhitelisted;
        // basic parameters
        uint256 decimals;
        uint256 weight; // customisation of index composition
        uint256 minProfitBps;
        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 maxGlobalShortSize;
    }

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

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"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":"address","name":"treasury","internalType":"address"}]},{"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":"event","name":"TreasuryTransferred","inputs":[{"type":"address","name":"previousTreasury","internalType":"address","indexed":true},{"type":"address","name":"newTreasury","internalType":"address","indexed":true}],"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":"nonpayable","outputs":[],"name":"transferTreasury","inputs":[{"type":"address","name":"newTreasury","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"weth","inputs":[]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60c06040523480156200001157600080fd5b5060405162003a2d38038062003a2d833981016040819052620000349162000163565b600160009081558190620000476200015f565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600280546001600160a01b0319166001600160a01b0383169081179091556040516000907febebcc22237fa047dcfebf54b185ec126c9b24d45f4bd2a18e4fa02e07308c40908290a3506001600160a01b038416620001115760405162461bcd60e51b81526004016200010890620001ff565b60405180910390fd5b6001600160a01b0383166200013a5760405162461bcd60e51b81526004016200010890620001be565b506001600160601b0319606093841b81166080529190921b1660a05260035562000266565b3390565b6000806000806080858703121562000179578384fd5b845162000186816200024d565b602086015190945062000199816200024d565b604086015160608701519194509250620001b3816200024d565b939692955090935050565b60208082526021908201527f50686c704d616e616765723a2077657468206973207a65726f206164647265736040820152607360f81b606082015260800190565b6020808252602e908201527f50686c704d616e616765723a2061646472657373657350726f7669646572206960408201526d73207a65726f206164647265737360901b606082015260800190565b6001600160a01b03811681146200026357600080fd5b50565b60805160601c60a05160601c61372a62000303600039806101545280610aaa5280610aeb5280610c105280610e1e528061287e528061290a52508061043e52806104d35280610f5e52806110b0528061122e52806112c3528061135852806116d05280611808528061191a5280611d8a5280611e1f5280611eb4528061213d528061224152806123b552806126b05280612745525061372a6000f3fe6080604052600436106101445760003560e01c80638da5cb5b116100b6578063c72c4d101161006f578063c72c4d101461038d578063d8a6021c146103a2578063dc21b44d146103c2578063e245b5af146103d7578063ed0d1c04146103f7578063f2fde38b146104195761019c565b80638da5cb5b146102e25780638fed0b2c146102f75780638ffc80a11461031757806395082d251461032a578063966be0751461033f578063a1acd3d51461035f5761019c565b8063352693151161010857806335269315146102415780633fc8cef31461025657806361d027b3146102785780636bd3b5a31461028d578063715018a6146102ad5780638b770e11146102c25761019c565b806303391476146101a157806303563e67146101d7578063124e61c6146101ec5780631e9049cf1461020c5780631ece366a146102215761019c565b3661019c57336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461019a5760405162461bcd60e51b8152600401610191906133dc565b60405180910390fd5b005b600080fd5b3480156101ad57600080fd5b506101c16101bc36600461303f565b610439565b6040516101ce9190613356565b60405180910390f35b3480156101e357600080fd5b506101c1610a50565b3480156101f857600080fd5b506101c161020736600461323a565b610a55565b34801561021857600080fd5b506101c1610b73565b34801561022d57600080fd5b506101c161023c366004613005565b610b7a565b34801561024d57600080fd5b506101c1610c08565b34801561026257600080fd5b5061026b610c0e565b6040516101ce9190613272565b34801561028457600080fd5b5061026b610c32565b34801561029957600080fd5b506101c16102a836600461303f565b610c41565b3480156102b957600080fd5b5061019a610c79565b3480156102ce57600080fd5b506101c16102dd366004612f50565b610d37565b3480156102ee57600080fd5b5061026b610d49565b34801561030357600080fd5b506101c1610312366004612fbc565b610d58565b6101c1610325366004613219565b610db2565b34801561033657600080fd5b506101c1610eaa565b34801561034b57600080fd5b5061019a61035a3660046131e9565b610ebb565b34801561036b57600080fd5b5061037f61037a366004612f88565b610f57565b6040516101ce929190613576565b34801561039957600080fd5b5061026b6110ae565b3480156103ae57600080fd5b5061019a6103bd366004612f50565b6110d2565b3480156103ce57600080fd5b5061019a611181565b3480156103e357600080fd5b506101c16103f236600461303f565b611915565b34801561040357600080fd5b5061040c611a61565b6040516101ce9190613312565b34801561042557600080fd5b5061019a610434366004612f50565b611ad0565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561049557600080fd5b505afa1580156104a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104cd9190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561052a57600080fd5b505afa15801561053e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105629190612f6c565b90506000826001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561059f57600080fd5b505afa1580156105b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d79190613201565b905060008060005b83811015610a2957604051630e468baf60e41b81526000906001600160a01b0388169063e468baf090610616908590600401613356565b60206040518083038186803b15801561062e57600080fd5b505afa158015610642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106669190612f6c565b90506000876001600160a01b031663cb67e3b1836040518263ffffffff1660e01b81526004016106969190613272565b6101206040518083038186803b1580156106af57600080fd5b505afa1580156106c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e79190613077565b90506000876001600160a01b03166376d69760848d6040518363ffffffff1660e01b81526004016107199291906132f7565b60206040518083038186803b15801561073157600080fd5b505afa158015610745573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107699190613201565b90506000896001600160a01b03166352f55eed856040518263ffffffff1660e01b81526004016107999190613272565b60206040518083038186803b1580156107b157600080fd5b505afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190613201565b602084015160a085015191925090156108255761081e610817600a83900a6108118587611be5565b90611c47565b8990611cae565b9750610a18565b60405163114f1b5560e31b81526000906001600160a01b038d1690638a78daa890610854908990600401613272565b60206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190613201565b905080156108e4576000806108ba888785610f57565b91509150806108d4576108cd8b83611cae565b9a506108e1565b6108de8a83611cae565b99505b50505b60405163783a2b6760e11b815261096b906001600160a01b038e169063f07456ce90610914908a90600401613272565b60206040518083038186803b15801561092c57600080fd5b505afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190613201565b8a90611cae565b985060008c6001600160a01b031663c3c7b9e9886040518263ffffffff1660e01b815260040161099b9190613272565b60206040518083038186803b1580156109b357600080fd5b505afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109eb9190613201565b9050610a13610a0c600a85900a61081188610a068987611d08565b90611be5565b8b90611cae565b995050505b5050600190930192506105df915050565b50818111610a4057610a3b8282611d08565b610a43565b60005b955050505050505b919050565b601281565b600060026000541415610a9d576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000908155610ad1337f0000000000000000000000000000000000000000000000000000000000000000878730611d65565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90610b20908490600401613356565b600060405180830381600087803b158015610b3a57600080fd5b505af1158015610b4e573d6000803e3d6000fd5b50610b66925050506001600160a01b038416826125a1565b6001600055949350505050565b6202a30081565b600060026000541415610bc2576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000556001600160a01b038516610bed5760405162461bcd60e51b81526004016101919061350a565b610bfa338686868661268b565b600160005595945050505050565b60035481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6002546001600160a01b031690565b600080610c4d83610439565b9050610c726c0c9f2c9cd04674edea4000000061081183670de0b6b3a7640000611be5565b9392505050565b610c81612bb3565b6001600160a01b0316610c92610d49565b6001600160a01b031614610ced576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60046020526000908152604090205481565b6001546001600160a01b031690565b600060026000541415610da0576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b6002600055610bfa3386868686611d65565b600060026000541415610dfa576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b600260005534610e1c5760405162461bcd60e51b8152600401610191906133a5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7757600080fd5b505af1158015610e8b573d6000803e3d6000fd5b5050505050610e9e33600034868661268b565b60016000559392505050565b6c0c9f2c9cd04674edea4000000081565b610ec3612bb3565b6001600160a01b0316610ed4610d49565b6001600160a01b031614610f2f576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6202a300811115610f525760405162461bcd60e51b81526004016101919061344a565b600355565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b158015610fb557600080fd5b505afa158015610fc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fed9190612f6c565b6001600160a01b03166362749803876040518263ffffffff1660e01b81526004016110189190613272565b60206040518083038186803b15801561103057600080fd5b505afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190613201565b905060008582116110825761107d8683611d08565b61108c565b61108c8287611d08565b9050600061109e836108118885611be5565b9450505084109050935093915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6110da612bb3565b6001600160a01b03166110eb610c32565b6001600160a01b0316146111305760405162461bcd60e51b815260040180806020018281038252602b815260200180613614602b913960400191505060405180910390fd5b6001600160a01b0381166111755760405162461bcd60e51b815260040180806020018281038252603181526020018061369a6031913960400191505060405180910390fd5b61117e81612bb7565b50565b600260005414156111c7576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000556111d4612bb3565b6001600160a01b03166111e5610c32565b6001600160a01b03161461122a5760405162461bcd60e51b815260040180806020018281038252602b815260200180613614602b913960400191505060405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561128557600080fd5b505afa158015611299573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bd9190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113529190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634bd9a9aa6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113af57600080fd5b505afa1580156113c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e79190612f6c565b905060005b836001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561142557600080fd5b505afa158015611439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145d9190613201565b8110156116cb57604051630e468baf60e41b81526000906001600160a01b0386169063e468baf090611493908590600401613356565b60206040518083038186803b1580156114ab57600080fd5b505afa1580156114bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e39190612f6c565b604051631e4aaa4f60e31b81529091506001600160a01b0386169063f255527890611514908490309060040161329f565b602060405180830381600087803b15801561152e57600080fd5b505af1158015611542573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115669190613201565b50604051631e4aaa4f60e31b81526001600160a01b0385169063f255527890611595908490309060040161329f565b600060405180830381600087803b1580156115af57600080fd5b505af11580156115c3573d6000803e3d6000fd5b5050604051631e4aaa4f60e31b81526001600160a01b038616925063f255527891506115f5908490309060040161329f565b600060405180830381600087803b15801561160f57600080fd5b505af1158015611623573d6000803e3d6000fd5b50506040516370a0823160e01b8152839250600091506001600160a01b038316906370a0823190611658903090600401613272565b60206040518083038186803b15801561167057600080fd5b505afa158015611684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a89190613201565b905080156116c0576116be30848360008061268b565b505b5050506001016113ec565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561172757600080fd5b505afa15801561173b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175f9190612f6c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161178a9190613272565b60206040518083038186803b1580156117a257600080fd5b505afa1580156117b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117da9190613201565b9050801561190a5730600090815260046020818152604080842093909355825163fd591dcd60e01b815292517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169363fd591dcd93818101939291829003018186803b15801561185157600080fd5b505afa158015611865573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118899190612f6c565b6001600160a01b031663a9059cbb33836040518363ffffffff1660e01b81526004016118b6929190613286565b602060405180830381600087803b1580156118d057600080fd5b505af11580156118e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611908919061305b565b505b505060016000555050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561197157600080fd5b505afa158015611985573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a99190612f6c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a199190613201565b905080611a36576c0c9f2c9cd04674edea40000000915050610a4b565b6000611a4184610439565b9050611a598261081183670de0b6b3a7640000611be5565b949350505050565b60408051600280825260608083018452926000929190602083019080368337019050509050611a906001610439565b81600081518110611a9d57fe5b602002602001018181525050611ab36000610439565b81600181518110611ac057fe5b6020908102919091010152905090565b611ad8612bb3565b6001600160a01b0316611ae9610d49565b6001600160a01b031614611b44576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611b895760405162461bcd60e51b81526004018080602001828103825260268152602001806135ee6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600082611bf457506000611c41565b82820282848281611c0157fe5b0414611c3e5760405162461bcd60e51b81526004018080602001828103825260218152602001806136796021913960400191505060405180910390fd5b90505b92915050565b6000808211611c9d576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611ca657fe5b049392505050565b600082820183811015611c3e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115611d5f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808411611d865760405162461bcd60e51b815260040161019190613541565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611de157600080fd5b505afa158015611df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e199190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e7657600080fd5b505afa158015611e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eae9190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f439190612f6c565b90506000611f516000610c41565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f8e57600080fd5b505afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190613201565b90506000611fd8826108118c86611be5565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120089190613272565b60206040518083038186803b15801561202057600080fd5b505afa158015612034573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120589190613201565b9050808211156120cc576001600160a01b0385166340c10f193061207c8585611d08565b6040518363ffffffff1660e01b8152600401612099929190613286565b600060405180830381600087803b1580156120b357600080fd5b505af11580156120c7573d6000803e3d6000fd5b505050505b856001600160a01b0316639dc29fac8e8d6040518363ffffffff1660e01b81526004016120fa929190613286565b600060405180830381600087803b15801561211457600080fd5b505af1158015612128573d6000803e3d6000fd5b50505050846001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561219457600080fd5b505afa1580156121a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cc9190612f6c565b846040518363ffffffff1660e01b81526004016121ea929190613286565b602060405180830381600087803b15801561220457600080fd5b505af1158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c919061305b565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561229857600080fd5b505afa1580156122ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d09190612f6c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561230957600080fd5b505afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190613108565b610180015190508b8414156123b157604051632413866560e01b81526001600160a01b0389169063241386659061237e9061271090600401613356565b600060405180830381600087803b15801561239857600080fd5b505af11580156123ac573d6000803e3d6000fd5b505050505b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561240c57600080fd5b505afa158015612420573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124449190612f6c565b6001600160a01b0316635bae42638f8d6040518363ffffffff1660e01b815260040161247192919061329f565b602060405180830381600087803b15801561248b57600080fd5b505af115801561249f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c39190613201565b90508c85141561252c57604051632413866560e01b81526001600160a01b038a16906324138665906124f9908590600401613356565b600060405180830381600087803b15801561251357600080fd5b505af1158015612527573d6000803e3d6000fd5b505050505b8b81101561254c5760405162461bcd60e51b815260040161019190613490565b7f87b9679bb9a4944bafa98c267e7cd4a00ab29fed48afdefae25f0fca5da279408f8f8f8989898760405161258797969594939291906132b9565b60405180910390a19e9d5050505050505050505050505050565b804710156125f6576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612641576040519150601f19603f3d011682016040523d82523d6000602084013e612646565b606091505b50509050806126865760405162461bcd60e51b815260040180806020018281038252603a81526020018061363f603a913960400191505060405180910390fd5b505050565b60008084116126ac5760405162461bcd60e51b815260040161019190613413565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561270757600080fd5b505afa15801561271b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273f9190612f6c565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561279c57600080fd5b505afa1580156127b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d49190612f6c565b905060006127e26001610c41565b90506000826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281f57600080fd5b505afa158015612833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128579190613201565b90506001600160a01b0389166129305760405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906128b59087908c90600401613286565b602060405180830381600087803b1580156128cf57600080fd5b505af11580156128e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612907919061305b565b507f0000000000000000000000000000000000000000000000000000000000000000985061296f565b6001600160a01b038a1630141561295a576129556001600160a01b038a16858a612c13565b61296f565b61296f6001600160a01b038a168b868b612c65565b60006001600160a01b038b163014612a0657604051635da69ed760e01b81526001600160a01b03861690635da69ed7906129af908d90309060040161329f565b602060405180830381600087803b1580156129c957600080fd5b505af11580156129dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a019190613201565b612a84565b60405163080d568b60e21b81526001600160a01b038616906320355a2c90612a32908d90600401613272565b602060405180830381600087803b158015612a4c57600080fd5b505af1158015612a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a849190613201565b905087811015612aa65760405162461bcd60e51b81526004016101919061335f565b60008315612ac157612abc846108118486611be5565b612ac3565b815b905087811015612ae55760405162461bcd60e51b8152600401610191906134c5565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990612b13908f908590600401613286565b600060405180830381600087803b158015612b2d57600080fd5b505af1158015612b41573d6000803e3d6000fd5b5050506001600160a01b038d1660009081526004602052604090819020429055517f38dc38b96482be64113daffd8d464ebda93e856b70ccfc605e69ccf892ab981e9150612b9c908e908e908e9089908990899089906132b9565b60405180910390a19b9a5050505050505050505050565b3390565b6002546040516001600160a01b038084169216907febebcc22237fa047dcfebf54b185ec126c9b24d45f4bd2a18e4fa02e07308c4090600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612686908490612cc5565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612cbf908590612cc5565b50505050565b6000612d1a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612d769092919063ffffffff16565b80519091501561268657808060200190516020811015612d3957600080fd5b50516126865760405162461bcd60e51b815260040180806020018281038252602a8152602001806136cb602a913960400191505060405180910390fd5b6060611a59848460008585612d8a85612e9b565b612ddb576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612e195780518252601f199092019160209182019101612dfa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612e7b576040519150601f19603f3d011682016040523d82523d6000602084013e612e80565b606091505b5091509150612e90828286612ea1565b979650505050505050565b3b151590565b60608315612eb0575081610c72565b825115612ec05782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612f0a578181015183820152602001612ef2565b50505050905090810190601f168015612f375780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8051610a4b816135bf565b600060208284031215612f61578081fd5b8135611c3e816135aa565b600060208284031215612f7d578081fd5b8151611c3e816135aa565b600080600060608486031215612f9c578182fd5b8335612fa7816135aa565b95602085013595506040909401359392505050565b60008060008060808587031215612fd1578081fd5b8435612fdc816135aa565b935060208501359250604085013591506060850135612ffa816135aa565b939692955090935050565b6000806000806080858703121561301a578384fd5b8435613025816135aa565b966020860135965060408601359560600135945092505050565b600060208284031215613050578081fd5b8135611c3e816135bf565b60006020828403121561306c578081fd5b8151611c3e816135bf565b600061012080838503121561308a578182fd5b61309381613586565b905061309e83612f45565b8152602083015160208201526040830151604082015260608301516060820152608083015160808201526130d460a08401612f45565b60a08201526130e560c08401612f45565b60c082015260e08381015190820152610100928301519281019290925250919050565b600061020080838503121561311b578182fd5b61312481613586565b905061312f83612f45565b815261313d60208401612f45565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101606131b0818501612f45565b9082015261018083810151908201526101a080840151908201526101c080840151908201526101e0928301519281019290925250919050565b6000602082840312156131fa578081fd5b5035919050565b600060208284031215613212578081fd5b5051919050565b6000806040838503121561322b578182fd5b50508035926020909101359150565b60008060006060848603121561324e578081fd5b83359250602084013591506040840135613267816135aa565b809150509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561334a5783518352928401929184019160010161332e565b50909695505050505050565b90815260200190565b60208082526026908201527f50686c704d616e616765723a20696e73756666696369656e74205553445048206040820152651bdd5d1c1d5d60d21b606082015260800190565b6020808252601e908201527f50686c704d616e616765723a20696e76616c6964206d73672e76616c75650000604082015260600190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c69642073656e6465720000000000604082015260600190565b6020808252601c908201527f50686c704d616e616765723a20696e76616c6964205f616d6f756e7400000000604082015260600190565b60208082526026908201527f50686c704d616e616765723a20696e76616c6964205f636f6f6c646f776e44756040820152653930ba34b7b760d11b606082015260800190565b6020808252818101527f50686c704d616e616765723a20696e73756666696369656e74206f7574707574604082015260600190565b60208082526025908201527f50686c704d616e616765723a20696e73756666696369656e742050484c50206f6040820152641d5d1c1d5d60da1b606082015260800190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c6964205f746f6b656e0000000000604082015260600190565b6020808252818101527f50686c704d616e616765723a20696e76616c6964205f70686c70416d6f756e74604082015260600190565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156135a257fe5b604052919050565b6001600160a01b038116811461117e57600080fd5b801515811461117e57600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737354726561737572794f776e61626c653a2063616c6c6572206973206e6f7420746865207472656173757279416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7754726561737572794f776e61626c653a206e657720747265617375727920697320746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a264697066735822122093e2cbc031d5988982f1e4f7675e74f781aba17983a6a1b5c361c93089eb6d7564736f6c63430007060033000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000000000000000000000000000000000000000038400000000000000000000000042a0744fbc3d5d103856d61d14d45871ef533379

Deployed ByteCode

0x6080604052600436106101445760003560e01c80638da5cb5b116100b6578063c72c4d101161006f578063c72c4d101461038d578063d8a6021c146103a2578063dc21b44d146103c2578063e245b5af146103d7578063ed0d1c04146103f7578063f2fde38b146104195761019c565b80638da5cb5b146102e25780638fed0b2c146102f75780638ffc80a11461031757806395082d251461032a578063966be0751461033f578063a1acd3d51461035f5761019c565b8063352693151161010857806335269315146102415780633fc8cef31461025657806361d027b3146102785780636bd3b5a31461028d578063715018a6146102ad5780638b770e11146102c25761019c565b806303391476146101a157806303563e67146101d7578063124e61c6146101ec5780631e9049cf1461020c5780631ece366a146102215761019c565b3661019c57336001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27161461019a5760405162461bcd60e51b8152600401610191906133dc565b60405180910390fd5b005b600080fd5b3480156101ad57600080fd5b506101c16101bc36600461303f565b610439565b6040516101ce9190613356565b60405180910390f35b3480156101e357600080fd5b506101c1610a50565b3480156101f857600080fd5b506101c161020736600461323a565b610a55565b34801561021857600080fd5b506101c1610b73565b34801561022d57600080fd5b506101c161023c366004613005565b610b7a565b34801561024d57600080fd5b506101c1610c08565b34801561026257600080fd5b5061026b610c0e565b6040516101ce9190613272565b34801561028457600080fd5b5061026b610c32565b34801561029957600080fd5b506101c16102a836600461303f565b610c41565b3480156102b957600080fd5b5061019a610c79565b3480156102ce57600080fd5b506101c16102dd366004612f50565b610d37565b3480156102ee57600080fd5b5061026b610d49565b34801561030357600080fd5b506101c1610312366004612fbc565b610d58565b6101c1610325366004613219565b610db2565b34801561033657600080fd5b506101c1610eaa565b34801561034b57600080fd5b5061019a61035a3660046131e9565b610ebb565b34801561036b57600080fd5b5061037f61037a366004612f88565b610f57565b6040516101ce929190613576565b34801561039957600080fd5b5061026b6110ae565b3480156103ae57600080fd5b5061019a6103bd366004612f50565b6110d2565b3480156103ce57600080fd5b5061019a611181565b3480156103e357600080fd5b506101c16103f236600461303f565b611915565b34801561040357600080fd5b5061040c611a61565b6040516101ce9190613312565b34801561042557600080fd5b5061019a610434366004612f50565b611ad0565b6000807f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561049557600080fd5b505afa1580156104a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104cd9190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561052a57600080fd5b505afa15801561053e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105629190612f6c565b90506000826001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561059f57600080fd5b505afa1580156105b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d79190613201565b905060008060005b83811015610a2957604051630e468baf60e41b81526000906001600160a01b0388169063e468baf090610616908590600401613356565b60206040518083038186803b15801561062e57600080fd5b505afa158015610642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106669190612f6c565b90506000876001600160a01b031663cb67e3b1836040518263ffffffff1660e01b81526004016106969190613272565b6101206040518083038186803b1580156106af57600080fd5b505afa1580156106c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e79190613077565b90506000876001600160a01b03166376d69760848d6040518363ffffffff1660e01b81526004016107199291906132f7565b60206040518083038186803b15801561073157600080fd5b505afa158015610745573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107699190613201565b90506000896001600160a01b03166352f55eed856040518263ffffffff1660e01b81526004016107999190613272565b60206040518083038186803b1580156107b157600080fd5b505afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190613201565b602084015160a085015191925090156108255761081e610817600a83900a6108118587611be5565b90611c47565b8990611cae565b9750610a18565b60405163114f1b5560e31b81526000906001600160a01b038d1690638a78daa890610854908990600401613272565b60206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190613201565b905080156108e4576000806108ba888785610f57565b91509150806108d4576108cd8b83611cae565b9a506108e1565b6108de8a83611cae565b99505b50505b60405163783a2b6760e11b815261096b906001600160a01b038e169063f07456ce90610914908a90600401613272565b60206040518083038186803b15801561092c57600080fd5b505afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190613201565b8a90611cae565b985060008c6001600160a01b031663c3c7b9e9886040518263ffffffff1660e01b815260040161099b9190613272565b60206040518083038186803b1580156109b357600080fd5b505afa1580156109c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109eb9190613201565b9050610a13610a0c600a85900a61081188610a068987611d08565b90611be5565b8b90611cae565b995050505b5050600190930192506105df915050565b50818111610a4057610a3b8282611d08565b610a43565b60005b955050505050505b919050565b601281565b600060026000541415610a9d576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000908155610ad1337f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27878730611d65565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a271690632e1a7d4d90610b20908490600401613356565b600060405180830381600087803b158015610b3a57600080fd5b505af1158015610b4e573d6000803e3d6000fd5b50610b66925050506001600160a01b038416826125a1565b6001600055949350505050565b6202a30081565b600060026000541415610bc2576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000556001600160a01b038516610bed5760405162461bcd60e51b81526004016101919061350a565b610bfa338686868661268b565b600160005595945050505050565b60035481565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b6002546001600160a01b031690565b600080610c4d83610439565b9050610c726c0c9f2c9cd04674edea4000000061081183670de0b6b3a7640000611be5565b9392505050565b610c81612bb3565b6001600160a01b0316610c92610d49565b6001600160a01b031614610ced576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60046020526000908152604090205481565b6001546001600160a01b031690565b600060026000541415610da0576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b6002600055610bfa3386868686611d65565b600060026000541415610dfa576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b600260005534610e1c5760405162461bcd60e51b8152600401610191906133a5565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a276001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7757600080fd5b505af1158015610e8b573d6000803e3d6000fd5b5050505050610e9e33600034868661268b565b60016000559392505050565b6c0c9f2c9cd04674edea4000000081565b610ec3612bb3565b6001600160a01b0316610ed4610d49565b6001600160a01b031614610f2f576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6202a300811115610f525760405162461bcd60e51b81526004016101919061344a565b600355565b60008060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b158015610fb557600080fd5b505afa158015610fc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fed9190612f6c565b6001600160a01b03166362749803876040518263ffffffff1660e01b81526004016110189190613272565b60206040518083038186803b15801561103057600080fd5b505afa158015611044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110689190613201565b905060008582116110825761107d8683611d08565b61108c565b61108c8287611d08565b9050600061109e836108118885611be5565b9450505084109050935093915050565b7f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c81565b6110da612bb3565b6001600160a01b03166110eb610c32565b6001600160a01b0316146111305760405162461bcd60e51b815260040180806020018281038252602b815260200180613614602b913960400191505060405180910390fd5b6001600160a01b0381166111755760405162461bcd60e51b815260040180806020018281038252603181526020018061369a6031913960400191505060405180910390fd5b61117e81612bb7565b50565b600260005414156111c7576040805162461bcd60e51b815260206004820152601f60248201526000805160206135ce833981519152604482015290519081900360640190fd5b60026000556111d4612bb3565b6001600160a01b03166111e5610c32565b6001600160a01b03161461122a5760405162461bcd60e51b815260040180806020018281038252602b815260200180613614602b913960400191505060405180910390fd5b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561128557600080fd5b505afa158015611299573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bd9190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113529190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316634bd9a9aa6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113af57600080fd5b505afa1580156113c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e79190612f6c565b905060005b836001600160a01b0316630842b0766040518163ffffffff1660e01b815260040160206040518083038186803b15801561142557600080fd5b505afa158015611439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145d9190613201565b8110156116cb57604051630e468baf60e41b81526000906001600160a01b0386169063e468baf090611493908590600401613356565b60206040518083038186803b1580156114ab57600080fd5b505afa1580156114bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e39190612f6c565b604051631e4aaa4f60e31b81529091506001600160a01b0386169063f255527890611514908490309060040161329f565b602060405180830381600087803b15801561152e57600080fd5b505af1158015611542573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115669190613201565b50604051631e4aaa4f60e31b81526001600160a01b0385169063f255527890611595908490309060040161329f565b600060405180830381600087803b1580156115af57600080fd5b505af11580156115c3573d6000803e3d6000fd5b5050604051631e4aaa4f60e31b81526001600160a01b038616925063f255527891506115f5908490309060040161329f565b600060405180830381600087803b15801561160f57600080fd5b505af1158015611623573d6000803e3d6000fd5b50506040516370a0823160e01b8152839250600091506001600160a01b038316906370a0823190611658903090600401613272565b60206040518083038186803b15801561167057600080fd5b505afa158015611684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a89190613201565b905080156116c0576116be30848360008061268b565b505b5050506001016113ec565b5060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561172757600080fd5b505afa15801561173b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175f9190612f6c565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161178a9190613272565b60206040518083038186803b1580156117a257600080fd5b505afa1580156117b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117da9190613201565b9050801561190a5730600090815260046020818152604080842093909355825163fd591dcd60e01b815292517f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b03169363fd591dcd93818101939291829003018186803b15801561185157600080fd5b505afa158015611865573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118899190612f6c565b6001600160a01b031663a9059cbb33836040518363ffffffff1660e01b81526004016118b6929190613286565b602060405180830381600087803b1580156118d057600080fd5b505af11580156118e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611908919061305b565b505b505060016000555050565b6000807f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561197157600080fd5b505afa158015611985573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a99190612f6c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a199190613201565b905080611a36576c0c9f2c9cd04674edea40000000915050610a4b565b6000611a4184610439565b9050611a598261081183670de0b6b3a7640000611be5565b949350505050565b60408051600280825260608083018452926000929190602083019080368337019050509050611a906001610439565b81600081518110611a9d57fe5b602002602001018181525050611ab36000610439565b81600181518110611ac057fe5b6020908102919091010152905090565b611ad8612bb3565b6001600160a01b0316611ae9610d49565b6001600160a01b031614611b44576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611b895760405162461bcd60e51b81526004018080602001828103825260268152602001806135ee6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600082611bf457506000611c41565b82820282848281611c0157fe5b0414611c3e5760405162461bcd60e51b81526004018080602001828103825260218152602001806136796021913960400191505060405180910390fd5b90505b92915050565b6000808211611c9d576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611ca657fe5b049392505050565b600082820183811015611c3e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115611d5f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808411611d865760405162461bcd60e51b815260040161019190613541565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611de157600080fd5b505afa158015611df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e199190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e7657600080fd5b505afa158015611e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eae9190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f0b57600080fd5b505afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f439190612f6c565b90506000611f516000610c41565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f8e57600080fd5b505afa158015611fa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc69190613201565b90506000611fd8826108118c86611be5565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120089190613272565b60206040518083038186803b15801561202057600080fd5b505afa158015612034573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120589190613201565b9050808211156120cc576001600160a01b0385166340c10f193061207c8585611d08565b6040518363ffffffff1660e01b8152600401612099929190613286565b600060405180830381600087803b1580156120b357600080fd5b505af11580156120c7573d6000803e3d6000fd5b505050505b856001600160a01b0316639dc29fac8e8d6040518363ffffffff1660e01b81526004016120fa929190613286565b600060405180830381600087803b15801561211457600080fd5b505af1158015612128573d6000803e3d6000fd5b50505050846001600160a01b031663a9059cbb7f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561219457600080fd5b505afa1580156121a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cc9190612f6c565b846040518363ffffffff1660e01b81526004016121ea929190613286565b602060405180830381600087803b15801561220457600080fd5b505af1158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c919061305b565b5060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561229857600080fd5b505afa1580156122ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d09190612f6c565b6001600160a01b031663b2a2353e6040518163ffffffff1660e01b81526004016102006040518083038186803b15801561230957600080fd5b505afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190613108565b610180015190508b8414156123b157604051632413866560e01b81526001600160a01b0389169063241386659061237e9061271090600401613356565b600060405180830381600087803b15801561239857600080fd5b505af11580156123ac573d6000803e3d6000fd5b505050505b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561240c57600080fd5b505afa158015612420573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124449190612f6c565b6001600160a01b0316635bae42638f8d6040518363ffffffff1660e01b815260040161247192919061329f565b602060405180830381600087803b15801561248b57600080fd5b505af115801561249f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c39190613201565b90508c85141561252c57604051632413866560e01b81526001600160a01b038a16906324138665906124f9908590600401613356565b600060405180830381600087803b15801561251357600080fd5b505af1158015612527573d6000803e3d6000fd5b505050505b8b81101561254c5760405162461bcd60e51b815260040161019190613490565b7f87b9679bb9a4944bafa98c267e7cd4a00ab29fed48afdefae25f0fca5da279408f8f8f8989898760405161258797969594939291906132b9565b60405180910390a19e9d5050505050505050505050505050565b804710156125f6576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612641576040519150601f19603f3d011682016040523d82523d6000602084013e612646565b606091505b50509050806126865760405162461bcd60e51b815260040180806020018281038252603a81526020018061363f603a913960400191505060405180910390fd5b505050565b60008084116126ac5760405162461bcd60e51b815260040161019190613413565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561270757600080fd5b505afa15801561271b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273f9190612f6c565b905060007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fd591dcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561279c57600080fd5b505afa1580156127b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d49190612f6c565b905060006127e26001610c41565b90506000826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281f57600080fd5b505afa158015612833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128579190613201565b90506001600160a01b0389166129305760405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27169063a9059cbb906128b59087908c90600401613286565b602060405180830381600087803b1580156128cf57600080fd5b505af11580156128e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612907919061305b565b507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27985061296f565b6001600160a01b038a1630141561295a576129556001600160a01b038a16858a612c13565b61296f565b61296f6001600160a01b038a168b868b612c65565b60006001600160a01b038b163014612a0657604051635da69ed760e01b81526001600160a01b03861690635da69ed7906129af908d90309060040161329f565b602060405180830381600087803b1580156129c957600080fd5b505af11580156129dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a019190613201565b612a84565b60405163080d568b60e21b81526001600160a01b038616906320355a2c90612a32908d90600401613272565b602060405180830381600087803b158015612a4c57600080fd5b505af1158015612a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a849190613201565b905087811015612aa65760405162461bcd60e51b81526004016101919061335f565b60008315612ac157612abc846108118486611be5565b612ac3565b815b905087811015612ae55760405162461bcd60e51b8152600401610191906134c5565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990612b13908f908590600401613286565b600060405180830381600087803b158015612b2d57600080fd5b505af1158015612b41573d6000803e3d6000fd5b5050506001600160a01b038d1660009081526004602052604090819020429055517f38dc38b96482be64113daffd8d464ebda93e856b70ccfc605e69ccf892ab981e9150612b9c908e908e908e9089908990899089906132b9565b60405180910390a19b9a5050505050505050505050565b3390565b6002546040516001600160a01b038084169216907febebcc22237fa047dcfebf54b185ec126c9b24d45f4bd2a18e4fa02e07308c4090600090a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612686908490612cc5565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612cbf908590612cc5565b50505050565b6000612d1a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612d769092919063ffffffff16565b80519091501561268657808060200190516020811015612d3957600080fd5b50516126865760405162461bcd60e51b815260040180806020018281038252602a8152602001806136cb602a913960400191505060405180910390fd5b6060611a59848460008585612d8a85612e9b565b612ddb576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612e195780518252601f199092019160209182019101612dfa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612e7b576040519150601f19603f3d011682016040523d82523d6000602084013e612e80565b606091505b5091509150612e90828286612ea1565b979650505050505050565b3b151590565b60608315612eb0575081610c72565b825115612ec05782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612f0a578181015183820152602001612ef2565b50505050905090810190601f168015612f375780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8051610a4b816135bf565b600060208284031215612f61578081fd5b8135611c3e816135aa565b600060208284031215612f7d578081fd5b8151611c3e816135aa565b600080600060608486031215612f9c578182fd5b8335612fa7816135aa565b95602085013595506040909401359392505050565b60008060008060808587031215612fd1578081fd5b8435612fdc816135aa565b935060208501359250604085013591506060850135612ffa816135aa565b939692955090935050565b6000806000806080858703121561301a578384fd5b8435613025816135aa565b966020860135965060408601359560600135945092505050565b600060208284031215613050578081fd5b8135611c3e816135bf565b60006020828403121561306c578081fd5b8151611c3e816135bf565b600061012080838503121561308a578182fd5b61309381613586565b905061309e83612f45565b8152602083015160208201526040830151604082015260608301516060820152608083015160808201526130d460a08401612f45565b60a08201526130e560c08401612f45565b60c082015260e08381015190820152610100928301519281019290925250919050565b600061020080838503121561311b578182fd5b61312481613586565b905061312f83612f45565b815261313d60208401612f45565b602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152506101606131b0818501612f45565b9082015261018083810151908201526101a080840151908201526101c080840151908201526101e0928301519281019290925250919050565b6000602082840312156131fa578081fd5b5035919050565b600060208284031215613212578081fd5b5051919050565b6000806040838503121561322b578182fd5b50508035926020909101359150565b60008060006060848603121561324e578081fd5b83359250602084013591506040840135613267816135aa565b809150509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561334a5783518352928401929184019160010161332e565b50909695505050505050565b90815260200190565b60208082526026908201527f50686c704d616e616765723a20696e73756666696369656e74205553445048206040820152651bdd5d1c1d5d60d21b606082015260800190565b6020808252601e908201527f50686c704d616e616765723a20696e76616c6964206d73672e76616c75650000604082015260600190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c69642073656e6465720000000000604082015260600190565b6020808252601c908201527f50686c704d616e616765723a20696e76616c6964205f616d6f756e7400000000604082015260600190565b60208082526026908201527f50686c704d616e616765723a20696e76616c6964205f636f6f6c646f776e44756040820152653930ba34b7b760d11b606082015260800190565b6020808252818101527f50686c704d616e616765723a20696e73756666696369656e74206f7574707574604082015260600190565b60208082526025908201527f50686c704d616e616765723a20696e73756666696369656e742050484c50206f6040820152641d5d1c1d5d60da1b606082015260800190565b6020808252601b908201527f50686c704d616e616765723a20696e76616c6964205f746f6b656e0000000000604082015260600190565b6020808252818101527f50686c704d616e616765723a20696e76616c6964205f70686c70416d6f756e74604082015260600190565b9182521515602082015260400190565b60405181810167ffffffffffffffff811182821017156135a257fe5b604052919050565b6001600160a01b038116811461117e57600080fd5b801515811461117e57600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737354726561737572794f776e61626c653a2063616c6c6572206973206e6f7420746865207472656173757279416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7754726561737572794f776e61626c653a206e657720747265617375727920697320746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a264697066735822122093e2cbc031d5988982f1e4f7675e74f781aba17983a6a1b5c361c93089eb6d7564736f6c63430007060033