false
true
0

Contract Address Details

0x3dC4033fF5c04FdE3369937434961ca47AC7cA26

Contract Name
Vault
Creator
0x64e7ff–1c04a3 at 0x34c723–497e03
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
244,103 Transfers
Gas Used
Fetching gas used...
Last Balance Update
26040867
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Vault




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




Optimization runs
200
EVM Version
istanbul




Verified at
2023-09-15T17:47:38.457317Z

Constructor Arguments

0x000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c

Arg [0] (address) : 0xb29ea150c870ea830d9890d94f326cb1b273ce8c

              

contracts/protocol/core/Vault.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../dependencies/openzeppelin/contracts/ReentrancyGuard.sol";
import "../../dependencies/openzeppelin/contracts/IERC20.sol";
import "../../dependencies/openzeppelin/contracts/SafeERC20.sol";
import "../../interfaces/IUSDPH.sol";
import "../../interfaces/IVault.sol";
import "../../interfaces/IVaultConfigurator.sol";
import "../../interfaces/IPhamePriceOracle.sol";
import "../libraries/helpers/Errors.sol";
import "../libraries/logic/TokenConfigsLogic.sol";
import "../libraries/utils/VaultUtils.sol";
import "../libraries/utils/GeneralUtils.sol";
import "../libraries/types/DataTypes.sol";

contract Vault is IVault, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using TokenConfigsLogic for DataTypes.TokenConfigs;

    uint256 public constant BASIS_POINTS_DIVISOR = 10000;
    uint256 public constant PRICE_PRECISION = 10 ** 30;
    uint256 public constant USDPH_DECIMALS = 18;
    uint256 public constant FUNDING_RATE_PRECISION = 1000000;

    IAddressesProvider public immutable override addressesProvider;

    DataTypes.VaultConfig private _vaultConfig;
    DataTypes.TokenConfigs private _tokenConfigs;

    // tokenBalances is used only to determine _transferIn values
    mapping(address => uint256) public override tokenBalances;

    // usdphAmounts tracks the amount of USDPH debt for each whitelisted token
    mapping(address => uint256) public override usdphAmounts;

    // poolAmounts tracks the number of received tokens that can be used for leverage
    // this is tracked separately from tokenBalances to exclude funds that are deposited as margin collateral
    mapping(address => uint256) public override poolAmounts;

    // reservedAmounts tracks the number of tokens reserved for open leverage positions
    mapping(address => uint256) public override reservedAmounts;

    // guaranteedUsd tracks the amount of USD that is "guaranteed" by opened leverage positions
    // this value is used to calculate the redemption values for selling of USDPH
    // this is an estimated amount, it is possible for the actual guaranteed value to be lower
    // in the case of sudden price decreases, the guaranteed value should be corrected
    // after liquidations are carried out
    mapping(address => uint256) public override guaranteedUsd;

    // cumulativeFundingRates tracks the funding rates based on utilization
    mapping(address => uint256) public override cumulativeFundingRates;
    // lastFundingTimes tracks the last time funding was updated for a token
    mapping(address => uint256) public override lastFundingTimes;

    // positions tracks all open positions
    mapping(bytes32 => Position) public positions;

    // feeReserves tracks the amount of fees per token
    mapping(address => uint256) public override feeReserves;

    mapping(address => uint256) public override globalShortSizes;

    constructor(IAddressesProvider addressesProvider_) {
        addressesProvider = addressesProvider_;
    }

    function setVaultConfig(
        DataTypes.VaultConfig calldata vaultConfig
    ) external override {
        _validateConfigurator();

        _vaultConfig = vaultConfig;
    }

    function getVaultConfig()
        external
        view
        override
        returns (DataTypes.VaultConfig memory)
    {
        return _vaultConfig;
    }

    function allWhitelistedTokensLength()
        external
        view
        override
        returns (uint256)
    {
        return _tokenConfigs.allWhitelistedTokens.length;
    }

    function totalTokenWeights() external view override returns (uint256) {
        return _tokenConfigs.totalTokenWeights;
    }

    function allWhitelistedTokens(
        uint256 i
    ) external view override returns (address) {
        return _tokenConfigs.allWhitelistedTokens[i];
    }

    function setTokenConfig(
        address _token,
        DataTypes.TokenConfig calldata tokenConfig
    ) external override {
        _validateConfigurator();
        _tokenConfigs.setTokenConfig(_token, tokenConfig);
    }

    function clearTokenConfig(address _token) external override {
        _validateConfigurator();
        _tokenConfigs.clearTokenConfig(_token);
    }

    function getTokenConfig(
        address _token
    ) external view override returns (DataTypes.TokenConfig memory) {
        return _tokenConfigs.tokenConfigs[_token];
    }

    function setUsdphAmount(address _token, uint256 _amount) external override {
        _validateConfigurator();

        uint256 usdphAmount = usdphAmounts[_token];
        if (_amount > usdphAmount) {
            _increaseUsdphAmount(_token, _amount.sub(usdphAmount));
            return;
        }

        _decreaseUsdphAmount(_token, usdphAmount.sub(_amount));
    }

    function withdrawFees(
        address _token,
        address _receiver
    ) external override returns (uint256) {
        _validateManager();
        uint256 amount = feeReserves[_token];
        if (amount == 0) {
            return 0;
        }
        feeReserves[_token] = 0;
        _transferOut(_token, amount, _receiver);
        return amount;
    }

    // deposit into the pool without minting USDPH tokens
    // useful in allowing the pool to become over-collaterised
    function directPoolDeposit(address _token) external override nonReentrant {
        _validate(
            _tokenConfigs.tokenConfigs[_token].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );
        uint256 tokenAmount = _transferIn(_token);
        _validate(tokenAmount > 0, Errors.V_INVALID_TOKEN_AMOUNT);
        _increasePoolAmount(_token, tokenAmount);
        emit DirectPoolDeposit(_token, tokenAmount);
    }

    function buyUSDPH(
        address _token,
        address _receiver
    ) external override nonReentrant returns (uint256) {
        _validateManager();
        _validate(
            _tokenConfigs.tokenConfigs[_token].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );

        address usdph = addressesProvider.getUsdph();

        uint256 tokenAmount = _transferIn(_token);
        _validate(tokenAmount > 0, Errors.V_INVALID_TOKEN_AMOUNT);

        updateCumulativeFundingRate(_token, _token);

        uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
            .getPrice(_token, false);

        uint256 usdphAmount = tokenAmount.mul(price).div(PRICE_PRECISION);
        usdphAmount = adjustForDecimals(usdphAmount, _token, usdph);
        _validate(usdphAmount > 0, Errors.V_INVALID_USDPH_AMOUNT);

        uint256 feeBps = VaultUtils.getBuyUsdphFeeBps(
            addressesProvider,
            _token,
            usdphAmount
        );
        (uint256 amountAfterFees, uint256 feeAmount) = _collectSwapFees(
            _token,
            tokenAmount,
            feeBps
        );
        uint256 mintAmount = amountAfterFees.mul(price).div(PRICE_PRECISION);
        mintAmount = adjustForDecimals(mintAmount, _token, usdph);

        _increaseUsdphAmount(_token, mintAmount);
        _increasePoolAmount(_token, amountAfterFees);

        IUSDPH(usdph).mint(_receiver, mintAmount);

        emit BuyUSDPH(_receiver, _token, tokenAmount, mintAmount, feeBps);

        _payLpFees(_token, feeAmount);
        return mintAmount;
    }

    function buyUSDPHwithoutFee(
        address _token
    ) external override nonReentrant returns (uint256) {
        _validateManager();
        _validate(
            _tokenConfigs.tokenConfigs[_token].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );

        address usdph = addressesProvider.getUsdph();

        uint256 tokenAmount = _transferIn(_token);
        _validate(tokenAmount > 0, Errors.V_INVALID_TOKEN_AMOUNT);

        updateCumulativeFundingRate(_token, _token);

        uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
            .getPrice(_token, false);

        uint256 usdphAmount = tokenAmount.mul(price).div(PRICE_PRECISION);
        usdphAmount = adjustForDecimals(usdphAmount, _token, usdph);
        _validate(usdphAmount > 0, Errors.V_INVALID_USDPH_AMOUNT);

        uint256 mintAmount = tokenAmount.mul(price).div(PRICE_PRECISION);
        mintAmount = adjustForDecimals(mintAmount, _token, usdph);

        _increaseUsdphAmount(_token, mintAmount);
        _increasePoolAmount(_token, tokenAmount);

        IUSDPH(usdph).mint(msg.sender, mintAmount);

        emit BuyUSDPH(msg.sender, _token, tokenAmount, mintAmount, 0);

        return mintAmount;
    }

    function sellUSDPH(
        address _token,
        address _receiver
    ) external override nonReentrant returns (uint256) {
        _validateManager();
        _validate(
            _tokenConfigs.tokenConfigs[_token].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );

        address usdph = addressesProvider.getUsdph();

        uint256 usdphAmount = _transferIn(usdph);
        _validate(usdphAmount > 0, Errors.V_INVALID_USDPH_AMOUNT);

        updateCumulativeFundingRate(_token, _token);

        uint256 redemptionAmount = getRedemptionAmount(_token, usdphAmount);
        _validate(redemptionAmount > 0, Errors.V_INVALID_REDEMPTION_AMOUNT);

        _decreaseUsdphAmount(_token, usdphAmount);
        _decreasePoolAmount(_token, redemptionAmount);

        IUSDPH(usdph).burn(address(this), usdphAmount);

        // the _transferIn call increased the value of tokenBalances[usdph]
        // usually decreases in token balances are synced by calling _transferOut
        // however, for usdph, the tokens are burnt, so tokenBalances should
        // be manually updated record the decrease in tokens
        tokenBalances[usdph] = IERC20(usdph).balanceOf(address(this));

        uint256 feeBps = VaultUtils.getSellUsdphFeeBps(
            addressesProvider,
            _token,
            usdphAmount
        );
        (uint256 amountOut, uint256 feeAmount) = _collectSwapFees(
            _token,
            redemptionAmount,
            feeBps
        );
        _validate(amountOut > 0, Errors.V_INVALID_AMOUNT_OUT);

        _transferOut(_token, amountOut, _receiver);

        emit SellUSDPH(_receiver, _token, usdphAmount, amountOut, feeBps);

        _payLpFees(_token, feeAmount);
        return amountOut;
    }

    function swap(
        address _tokenIn,
        address _tokenOut,
        address _receiver
    ) external override nonReentrant returns (uint256) {
        _validate(_vaultConfig.isSwapEnabled, Errors.V_SWAPS_NOT_ENABLED);
        _validate(
            _tokenConfigs.tokenConfigs[_tokenIn].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );
        _validate(
            _tokenConfigs.tokenConfigs[_tokenOut].isWhitelisted,
            Errors.V_TOKEN_NOT_WHITELISTED
        );
        _validate(_tokenIn != _tokenOut, Errors.V_SAME_TOKEN);

        updateCumulativeFundingRate(_tokenIn, _tokenIn);
        updateCumulativeFundingRate(_tokenOut, _tokenOut);

        uint256 amountIn = _transferIn(_tokenIn);
        _validate(amountIn > 0, Errors.V_INVALID_AMOUNT_IN);

        IPhamePriceOracle priceOracle = IPhamePriceOracle(
            addressesProvider.getPriceOracle()
        );
        uint256 priceIn = priceOracle.getPrice(_tokenIn, false);
        uint256 priceOut = priceOracle.getPrice(_tokenOut, true);

        uint256 amountOut = amountIn.mul(priceIn).div(priceOut);
        amountOut = adjustForDecimals(amountOut, _tokenIn, _tokenOut);

        // adjust usdphAmounts by the same usdphAmount as debt is shifted between the assets
        uint256 usdphAmount = amountIn.mul(priceIn).div(PRICE_PRECISION);
        usdphAmount = adjustForDecimals(
            usdphAmount,
            _tokenIn,
            addressesProvider.getUsdph()
        );

        uint256 feeBps = VaultUtils.getSwapFeeBps(
            addressesProvider,
            _tokenIn,
            _tokenOut,
            usdphAmount
        );
        (uint256 amountOutAfterFees, uint256 feeAmount) = _collectSwapFees(
            _tokenOut,
            amountOut,
            feeBps
        );

        _increaseUsdphAmount(_tokenIn, usdphAmount);
        _decreaseUsdphAmount(_tokenOut, usdphAmount);

        _increasePoolAmount(_tokenIn, amountIn);
        _decreasePoolAmount(_tokenOut, amountOut);

        _validate(
            poolAmounts[_tokenOut] >=
                _tokenConfigs.tokenConfigs[_tokenOut].bufferAmount,
            Errors.V_POOL_LESS_THAN_BUFFER
        );

        _transferOut(_tokenOut, amountOutAfterFees, _receiver);

        emit Swap(
            _receiver,
            _tokenIn,
            _tokenOut,
            amountIn,
            amountOut,
            amountOutAfterFees,
            feeBps
        );

        _payLpFees(_tokenOut, feeAmount);

        return amountOutAfterFees;
    }

    function increasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external override nonReentrant {
        _validateRouter();
        _tokenConfigs.validateTokens(_collateralToken, _indexToken, _isLong);
        require(_vaultConfig.isLeverageEnabled, Errors.VU_LEVERAGE_NOT_ENABLED);

        updateCumulativeFundingRate(_collateralToken, _indexToken);

        bytes32 key = _getPositionKey(
            _account,
            _collateralToken,
            _indexToken,
            _isLong
        );
        Position storage position = positions[key];

        uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
            .getPrice(_indexToken, _isLong);

        if (position.size == 0) {
            position.averagePrice = price;
        }

        if (position.size > 0 && _sizeDelta > 0) {
            position.averagePrice = getNextAveragePrice(
                _indexToken,
                position.size,
                position.averagePrice,
                _isLong,
                price,
                _sizeDelta,
                position.lastIncreasedTime
            );
        }

        (uint256 fee, uint256 feeAmount) = _collectMarginFees(
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            _sizeDelta,
            position.size,
            position.entryFundingRate
        );
        uint256 collateralDelta = _transferIn(_collateralToken);
        uint256 collateralDeltaUsd = tokenToUsdMin(
            _collateralToken,
            collateralDelta
        );

        position.collateral = position.collateral.add(collateralDeltaUsd);
        _validate(
            position.collateral >= fee,
            Errors.V_INSUFFICIENT_COLLATERAL_FOR_FEES
        );

        position.collateral = position.collateral.sub(fee);
        position.entryFundingRate = getEntryFundingRate(
            _collateralToken,
            _indexToken,
            _isLong
        );
        position.size = position.size.add(_sizeDelta);
        position.lastIncreasedTime = block.timestamp;

        _validate(position.size > 0, Errors.V_INVALID_POSITION_SIZE);
        _validatePosition(position.size, position.collateral);
        validateLiquidation(
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            true
        );

        // reserve tokens to pay profits on the position
        uint256 reserveDelta = usdToToken(_collateralToken, _sizeDelta, true);
        position.reserveAmount = position.reserveAmount.add(reserveDelta);
        _increaseReservedAmount(_collateralToken, reserveDelta);

        if (_isLong) {
            // guaranteedUsd stores the sum of (position.size - position.collateral) for all positions
            // if a fee is charged on the collateral then guaranteedUsd should be increased by that fee amount
            // since (position.size - position.collateral) would have increased by `fee`
            _increaseGuaranteedUsd(_collateralToken, _sizeDelta.add(fee));
            _decreaseGuaranteedUsd(_collateralToken, collateralDeltaUsd);
            // treat the deposited collateral as part of the pool
            _increasePoolAmount(_collateralToken, collateralDelta);
            // fees need to be deducted from the pool since fees are deducted from position.collateral
            // and collateral is treated as part of the pool
            _decreasePoolAmount(
                _collateralToken,
                usdToToken(_collateralToken, fee, false)
            );
        } else {
            _increaseGlobalShortSize(_indexToken, _sizeDelta);
        }

        emit IncreasePosition(
            key,
            _account,
            _collateralToken,
            _indexToken,
            collateralDeltaUsd,
            _sizeDelta,
            _isLong,
            price,
            fee
        );
        emit UpdatePosition(
            key,
            position.size,
            position.collateral,
            position.averagePrice,
            position.entryFundingRate,
            position.reserveAmount,
            position.realisedPnl,
            price
        );

        _payLpFees(_collateralToken, feeAmount);
    }

    function decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external override nonReentrant returns (uint256) {
        _validateRouter();
        return
            _decreasePosition(
                _account,
                _collateralToken,
                _indexToken,
                _collateralDelta,
                _sizeDelta,
                _isLong,
                _receiver
            );
    }

    function _decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) private returns (uint256) {
        updateCumulativeFundingRate(_collateralToken, _indexToken);

        bytes32 key = _getPositionKey(
            _account,
            _collateralToken,
            _indexToken,
            _isLong
        );
        Position storage position = positions[key];
        _validate(position.size > 0, Errors.V_EMPTY_POSITION);
        _validate(position.size >= _sizeDelta, Errors.V_POSITION_SIZE_EXCEEDED);
        _validate(
            position.collateral >= _collateralDelta,
            Errors.V_POSITION_COLLATERAL_EXCEEDED
        );

        uint256 collateral = position.collateral;
        // scrop variables to avoid stack too deep errors
        {
            uint256 reserveDelta = position.reserveAmount.mul(_sizeDelta).div(
                position.size
            );
            position.reserveAmount = position.reserveAmount.sub(reserveDelta);
            _decreaseReservedAmount(_collateralToken, reserveDelta);
        }

        (uint256 usdOut, uint256 usdOutAfterFee) = _reduceCollateral(
            _account,
            _collateralToken,
            _indexToken,
            _collateralDelta,
            _sizeDelta,
            _isLong
        );

        if (position.size != _sizeDelta) {
            position.entryFundingRate = getEntryFundingRate(
                _collateralToken,
                _indexToken,
                _isLong
            );
            position.size = position.size.sub(_sizeDelta);

            _validatePosition(position.size, position.collateral);
            validateLiquidation(
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                true
            );

            if (_isLong) {
                _increaseGuaranteedUsd(
                    _collateralToken,
                    collateral.sub(position.collateral)
                );
                _decreaseGuaranteedUsd(_collateralToken, _sizeDelta);
            }

            uint256 price = IPhamePriceOracle(
                addressesProvider.getPriceOracle()
            ).getPrice(_indexToken, !_isLong);
            emit DecreasePosition(
                key,
                _account,
                _collateralToken,
                _indexToken,
                _collateralDelta,
                _sizeDelta,
                _isLong,
                price,
                usdOut.sub(usdOutAfterFee)
            );
            emit UpdatePosition(
                key,
                position.size,
                position.collateral,
                position.averagePrice,
                position.entryFundingRate,
                position.reserveAmount,
                position.realisedPnl,
                price
            );
        } else {
            if (_isLong) {
                _increaseGuaranteedUsd(_collateralToken, collateral);
                _decreaseGuaranteedUsd(_collateralToken, _sizeDelta);
            }

            uint256 price = IPhamePriceOracle(
                addressesProvider.getPriceOracle()
            ).getPrice(_indexToken, !_isLong);
            emit DecreasePosition(
                key,
                _account,
                _collateralToken,
                _indexToken,
                _collateralDelta,
                _sizeDelta,
                _isLong,
                price,
                usdOut.sub(usdOutAfterFee)
            );
            emit ClosePosition(
                key,
                position.size,
                position.collateral,
                position.averagePrice,
                position.entryFundingRate,
                position.reserveAmount,
                position.realisedPnl
            );

            delete positions[key];
        }

        if (!_isLong) {
            _decreaseGlobalShortSize(_indexToken, _sizeDelta);
        }

        if (usdOut > 0) {
            if (_isLong) {
                _decreasePoolAmount(
                    _collateralToken,
                    usdToToken(_collateralToken, usdOut, false)
                );
            }
            uint256 amountOutAfterFees = usdToToken(
                _collateralToken,
                usdOutAfterFee,
                false
            );
            _transferOut(_collateralToken, amountOutAfterFees, _receiver);
            return amountOutAfterFees;
        }

        return 0;
    }

    function liquidatePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        address _feeReceiver
    ) external override nonReentrant {
        // only position manager can liquidate
        _validate(
            addressesProvider.getPositionManager() == msg.sender,
            Errors.V_INVALID_LIQUIDATOR
        );

        updateCumulativeFundingRate(_collateralToken, _indexToken);

        bytes32 key = _getPositionKey(
            _account,
            _collateralToken,
            _indexToken,
            _isLong
        );
        Position memory position = positions[key];
        _validate(position.size > 0, Errors.V_EMPTY_POSITION);

        (uint256 liquidationState, uint256 marginFees) = validateLiquidation(
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            false
        );
        _validate(
            liquidationState != 0,
            Errors.V_POSITION_CANNOT_BE_LIQUIDATED
        );
        if (liquidationState == 2) {
            // max leverage exceeded but there is collateral remaining after deducting losses so decreasePosition instead
            _decreasePosition(
                _account,
                _collateralToken,
                _indexToken,
                0,
                position.size,
                _isLong,
                _account
            );
            return;
        }

        uint256 feeTokens = usdToToken(_collateralToken, marginFees, false);
        feeReserves[_collateralToken] = feeReserves[_collateralToken].add(
            feeTokens
        );
        emit CollectMarginFees(_collateralToken, marginFees, feeTokens);

        _decreaseReservedAmount(_collateralToken, position.reserveAmount);
        if (_isLong) {
            _decreaseGuaranteedUsd(
                _collateralToken,
                position.size.sub(position.collateral)
            );
            _decreasePoolAmount(
                _collateralToken,
                usdToToken(_collateralToken, marginFees, false)
            );
        }

        uint256 markPrice = IPhamePriceOracle(
            addressesProvider.getPriceOracle()
        ).getPrice(_indexToken, !_isLong);
        emit LiquidatePosition(
            key,
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            position.size,
            position.collateral,
            position.reserveAmount,
            position.realisedPnl,
            markPrice
        );

        if (!_isLong && marginFees < position.collateral) {
            uint256 remainingCollateral = position.collateral.sub(marginFees);
            _increasePoolAmount(
                _collateralToken,
                usdToToken(_collateralToken, remainingCollateral, false)
            );
        }

        if (!_isLong) {
            _decreaseGlobalShortSize(_indexToken, position.size);
        }

        delete positions[key];

        // pay the fee receiver using the pool, we assume that in general the liquidated amount should be sufficient to cover
        // the liquidation fees
        uint256 liquidationFeeUsd = _vaultConfig.liquidationFeeUsd;
        _decreasePoolAmount(
            _collateralToken,
            usdToToken(_collateralToken, liquidationFeeUsd, false)
        );
        _transferOut(
            _collateralToken,
            usdToToken(_collateralToken, liquidationFeeUsd, false),
            _feeReceiver
        );

        _payLpFees(_collateralToken, feeTokens);
    }

    // validateLiquidation returns (state, fees)
    function validateLiquidation(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        bool _raise
    ) public view override returns (uint256, uint256) {
        return
            VaultUtils.validateLiquidation(
                addressesProvider,
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                _raise
            );
    }

    function getRedemptionAmount(
        address _token,
        uint256 _usdphAmount
    ) public view override returns (uint256) {
        uint256 price = IPhamePriceOracle(addressesProvider.getPriceOracle())
            .getPrice(_token, true);
        uint256 redemptionAmount = _usdphAmount.mul(PRICE_PRECISION).div(price);
        return
            adjustForDecimals(
                redemptionAmount,
                addressesProvider.getUsdph(),
                _token
            );
    }

    function getRedemptionCollateral(
        address _token
    ) public view returns (uint256) {
        if (_tokenConfigs.tokenConfigs[_token].isStable) {
            return poolAmounts[_token];
        }
        uint256 collateral = usdToToken(_token, guaranteedUsd[_token], false);
        return collateral.add(poolAmounts[_token]).sub(reservedAmounts[_token]);
    }

    function getRedemptionCollateralUsd(
        address _token
    ) public view returns (uint256) {
        return tokenToUsdMin(_token, getRedemptionCollateral(_token));
    }

    function adjustForDecimals(
        uint256 _amount,
        address _tokenDiv,
        address _tokenMul
    ) public view returns (uint256) {
        address usdph = addressesProvider.getUsdph();
        uint256 decimalsDiv = _tokenDiv == usdph
            ? USDPH_DECIMALS
            : _tokenConfigs.tokenConfigs[_tokenDiv].decimals;
        uint256 decimalsMul = _tokenMul == usdph
            ? USDPH_DECIMALS
            : _tokenConfigs.tokenConfigs[_tokenMul].decimals;
        return _amount.mul(10 ** decimalsMul).div(10 ** decimalsDiv);
    }

    function tokenToUsdMin(
        address _token,
        uint256 _tokenAmount
    ) public view override returns (uint256) {
        if (_tokenAmount == 0) {
            return 0;
        }
        return
            _tokenAmount
                .mul(
                    IPhamePriceOracle(addressesProvider.getPriceOracle())
                        .getPrice(_token, false)
                )
                .div(10 ** _tokenConfigs.tokenConfigs[_token].decimals);
    }

    function usdToToken(
        address _token,
        uint256 _usdAmount,
        bool _maximise
    ) private view returns (uint256) {
        if (_usdAmount == 0) {
            return 0;
        }
        return
            _usdAmount
                .mul(10 ** _tokenConfigs.tokenConfigs[_token].decimals)
                .div(
                    IPhamePriceOracle(addressesProvider.getPriceOracle())
                        .getPrice(_token, !_maximise)
                );
    }

    function getPosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    )
        public
        view
        override
        returns (
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            bool,
            uint256
        )
    {
        Position memory position = positions[
            _getPositionKey(_account, _collateralToken, _indexToken, _isLong)
        ];
        uint256 realisedPnl = position.realisedPnl > 0
            ? uint256(position.realisedPnl)
            : uint256(-position.realisedPnl);
        return (
            position.size, // 0
            position.collateral, // 1
            position.averagePrice, // 2
            position.entryFundingRate, // 3
            position.reserveAmount, // 4
            realisedPnl, // 5
            position.realisedPnl >= 0, // 6
            position.lastIncreasedTime // 7
        );
    }

    function updateCumulativeFundingRate(
        address _collateralToken,
        address _indexToken
    ) public {
        bool shouldUpdate = VaultUtils.updateCumulativeFundingRate(
            _collateralToken,
            _indexToken
        );
        if (!shouldUpdate) {
            return;
        }

        uint256 fundingInterval = _vaultConfig.fundingInterval;

        if (lastFundingTimes[_collateralToken] == 0) {
            lastFundingTimes[_collateralToken] = block
                .timestamp
                .div(fundingInterval)
                .mul(fundingInterval);
            return;
        }

        if (
            lastFundingTimes[_collateralToken].add(fundingInterval) >
            block.timestamp
        ) {
            return;
        }

        uint256 fundingRate = getNextFundingRate(_collateralToken);
        cumulativeFundingRates[_collateralToken] = cumulativeFundingRates[
            _collateralToken
        ].add(fundingRate);
        lastFundingTimes[_collateralToken] = block
            .timestamp
            .div(fundingInterval)
            .mul(fundingInterval);

        emit UpdateFundingRate(
            _collateralToken,
            cumulativeFundingRates[_collateralToken]
        );
    }

    function getNextFundingRate(
        address _token
    ) public view override returns (uint256) {
        return VaultUtils.getNextFundingRate(addressesProvider, _token);
    }

    // for longs: nextAveragePrice = (nextPrice * nextSize)/ (nextSize + delta)
    // for shorts: nextAveragePrice = (nextPrice * nextSize) / (nextSize - delta)
    function getNextAveragePrice(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _nextPrice,
        uint256 _sizeDelta,
        uint256 _lastIncreasedTime
    ) public view returns (uint256) {
        (bool hasProfit, uint256 delta) = getDelta(
            _indexToken,
            _size,
            _averagePrice,
            _isLong,
            _lastIncreasedTime
        );
        uint256 nextSize = _size.add(_sizeDelta);
        uint256 divisor;
        if (_isLong) {
            divisor = hasProfit ? nextSize.add(delta) : nextSize.sub(delta);
        } else {
            divisor = hasProfit ? nextSize.sub(delta) : nextSize.add(delta);
        }
        return _nextPrice.mul(nextSize).div(divisor);
    }

    function getDelta(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) public view override returns (bool, uint256) {
        return
            VaultUtils.getDelta(
                addressesProvider,
                _indexToken,
                _size,
                _averagePrice,
                _isLong,
                _lastIncreasedTime
            );
    }

    function getEntryFundingRate(
        address _collateralToken,
        address _indexToken,
        bool _isLong
    ) public view returns (uint256) {
        return
            VaultUtils.getEntryFundingRate(
                this,
                _collateralToken,
                _indexToken,
                _isLong
            );
    }

    function getFundingFee(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _size,
        uint256 _entryFundingRate
    ) public view returns (uint256) {
        return
            VaultUtils.getFundingFee(
                this,
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                _size,
                _entryFundingRate
            );
    }

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

    function _getPositionKey(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    ) private pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    _account,
                    _collateralToken,
                    _indexToken,
                    _isLong
                )
            );
    }

    function _reduceCollateral(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong
    ) private returns (uint256, uint256) {
        Position storage position;
        bool hasProfit;
        uint256 adjustedDelta;
        // scope variables to avoid stack too deep errors
        {
            bytes32 key = _getPositionKey(
                _account,
                _collateralToken,
                _indexToken,
                _isLong
            );
            position = positions[key];
            (bool _hasProfit, uint256 delta) = getDelta(
                _indexToken,
                position.size,
                position.averagePrice,
                _isLong,
                position.lastIncreasedTime
            );
            hasProfit = _hasProfit;
            // get the proportional change in pnl
            adjustedDelta = _sizeDelta.mul(delta).div(position.size);
            emit UpdatePnl(key, hasProfit, adjustedDelta);
        }

        (uint256 fee, uint256 feeAmount) = _collectMarginFees(
            _account,
            _collateralToken,
            _indexToken,
            _isLong,
            _sizeDelta,
            position.size,
            position.entryFundingRate
        );

        uint256 usdOut;
        // transfer profits out
        if (hasProfit && adjustedDelta > 0) {
            usdOut = adjustedDelta;
            position.realisedPnl = position.realisedPnl + int256(adjustedDelta);

            // pay out realised profits from the pool amount for short positions
            if (!_isLong) {
                uint256 tokenAmount = usdToToken(
                    _collateralToken,
                    adjustedDelta,
                    false
                );
                _decreasePoolAmount(_collateralToken, tokenAmount);
            }
        }

        if (!hasProfit && adjustedDelta > 0) {
            position.collateral = position.collateral.sub(adjustedDelta);

            // transfer realised losses to the pool for short positions
            // realised losses for long positions are not transferred here as
            // _increasePoolAmount was already called in increasePosition for longs
            if (!_isLong) {
                uint256 tokenAmount = usdToToken(
                    _collateralToken,
                    adjustedDelta,
                    false
                );
                _increasePoolAmount(_collateralToken, tokenAmount);
            }

            position.realisedPnl = position.realisedPnl - int256(adjustedDelta);
        }

        // reduce the position's collateral by _collateralDelta
        // transfer _collateralDelta out
        if (_collateralDelta > 0) {
            usdOut = usdOut.add(_collateralDelta);
            position.collateral = position.collateral.sub(_collateralDelta);
        }

        // if the position will be closed, then transfer the remaining collateral out
        if (position.size == _sizeDelta) {
            usdOut = usdOut.add(position.collateral);
            position.collateral = 0;
        }

        // if the usdOut is more than the fee then deduct the fee from the usdOut directly
        // else deduct the fee from the position's collateral
        uint256 usdOutAfterFee = usdOut;
        if (usdOut > fee) {
            usdOutAfterFee = usdOut.sub(fee);
        } else {
            position.collateral = position.collateral.sub(fee);
            if (_isLong) {
                uint256 feeTokens = usdToToken(_collateralToken, fee, false);
                _decreasePoolAmount(_collateralToken, feeTokens);
            }
        }

        _payLpFees(_collateralToken, feeAmount);

        return (usdOut, usdOutAfterFee);
    }

    function _validatePosition(
        uint256 _size,
        uint256 _collateral
    ) private pure {
        if (_size == 0) {
            _validate(
                _collateral == 0,
                Errors.V_COLLATERAL_SHOULD_BE_WITHDRAWN
            );
            return;
        }
        _validate(
            _size >= _collateral,
            Errors.V_SIZE_MUST_BE_MORE_THAN_COLLATERAL
        );
    }

    function _collectSwapFees(
        address _token,
        uint256 _amount,
        uint256 _feeBps
    ) private returns (uint256, uint256) {
        uint256 afterFeeAmount = _amount
            .mul(BASIS_POINTS_DIVISOR.sub(_feeBps))
            .div(BASIS_POINTS_DIVISOR);
        uint256 feeAmount = _amount.sub(afterFeeAmount);
        feeReserves[_token] = feeReserves[_token].add(feeAmount);
        emit CollectSwapFees(
            _token,
            tokenToUsdMin(_token, feeAmount),
            feeAmount
        );
        return (afterFeeAmount, feeAmount);
    }

    function _payLpFees(address token, uint256 feeAmount) private {
        uint256 lpFee = feeAmount
            .mul(BASIS_POINTS_DIVISOR.sub(_vaultConfig.stakingBps))
            .div(BASIS_POINTS_DIVISOR);
        if (lpFee > 0) {
            feeReserves[token] = feeReserves[token].sub(lpFee);
            poolAmounts[token] = poolAmounts[token].add(lpFee);
            emit PayLpFees(token, lpFee);
        }
    }

    function _collectMarginFees(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta,
        uint256 _size,
        uint256 _entryFundingRate
    ) private returns (uint256, uint256) {
        uint256 feeUsd = VaultUtils
            .getPositionFee(
                addressesProvider,
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                _sizeDelta
            )
            .add(
                getFundingFee(
                    _account,
                    _collateralToken,
                    _indexToken,
                    _isLong,
                    _size,
                    _entryFundingRate
                )
            );

        uint256 feeTokens = usdToToken(_collateralToken, feeUsd, false);
        feeReserves[_collateralToken] = feeReserves[_collateralToken].add(
            feeTokens
        );
        emit CollectMarginFees(_collateralToken, feeUsd, feeTokens);

        return (feeUsd, feeTokens);
    }

    function _transferIn(address _token) private returns (uint256) {
        uint256 prevBalance = tokenBalances[_token];
        uint256 nextBalance = IERC20(_token).balanceOf(address(this));
        tokenBalances[_token] = nextBalance;

        return nextBalance.sub(prevBalance);
    }

    function _transferOut(
        address _token,
        uint256 _amount,
        address _receiver
    ) private {
        IERC20(_token).safeTransfer(_receiver, _amount);
        tokenBalances[_token] = IERC20(_token).balanceOf(address(this));
    }

    function _increasePoolAmount(address _token, uint256 _amount) private {
        poolAmounts[_token] = poolAmounts[_token].add(_amount);
        uint256 balance = IERC20(_token).balanceOf(address(this));
        _validate(
            poolAmounts[_token] <= balance,
            Errors.V_POOL_AMOUNT_EXCEEDS_BALANCE
        );
        emit IncreasePoolAmount(_token, _amount);
    }

    function _decreasePoolAmount(address _token, uint256 _amount) private {
        poolAmounts[_token] = poolAmounts[_token].sub(_amount);
        _validate(
            reservedAmounts[_token] <= poolAmounts[_token],
            Errors.V_RESERVE_EXCEEDS_POOL
        );
        emit DecreasePoolAmount(_token, _amount);
    }

    function _increaseUsdphAmount(address _token, uint256 _amount) private {
        usdphAmounts[_token] = usdphAmounts[_token].add(_amount);
        uint256 maxUsdphAmount = _tokenConfigs
            .tokenConfigs[_token]
            .maxUsdphAmount;
        if (maxUsdphAmount != 0) {
            _validate(
                usdphAmounts[_token] <= maxUsdphAmount,
                Errors.V_MAX_USDPH_EXCEEDED
            );
        }
        emit IncreaseUsdphAmount(_token, _amount);
    }

    function _decreaseUsdphAmount(address _token, uint256 _amount) private {
        uint256 value = usdphAmounts[_token];
        // since USDPH can be minted using multiple assets
        // it is possible for the USDPH debt for a single asset to be less than zero
        // the USDPH debt is capped to zero for this case
        if (value <= _amount) {
            usdphAmounts[_token] = 0;
            emit DecreaseUsdphAmount(_token, value);
            return;
        }
        usdphAmounts[_token] = value.sub(_amount);
        emit DecreaseUsdphAmount(_token, _amount);
    }

    function _increaseReservedAmount(address _token, uint256 _amount) private {
        reservedAmounts[_token] = reservedAmounts[_token].add(_amount);
        _validate(
            reservedAmounts[_token] <= poolAmounts[_token],
            Errors.V_RESERVE_EXCEEDS_POOL
        );
        emit IncreaseReservedAmount(_token, _amount);
    }

    function _decreaseReservedAmount(address _token, uint256 _amount) private {
        reservedAmounts[_token] = reservedAmounts[_token].sub(
            _amount,
            "Vault: insufficient reserve"
        );
        emit DecreaseReservedAmount(_token, _amount);
    }

    function _increaseGuaranteedUsd(
        address _token,
        uint256 _usdAmount
    ) private {
        guaranteedUsd[_token] = guaranteedUsd[_token].add(_usdAmount);
        emit IncreaseGuaranteedUsd(_token, _usdAmount);
    }

    function _decreaseGuaranteedUsd(
        address _token,
        uint256 _usdAmount
    ) private {
        guaranteedUsd[_token] = guaranteedUsd[_token].sub(_usdAmount);
        emit DecreaseGuaranteedUsd(_token, _usdAmount);
    }

    function _increaseGlobalShortSize(address _token, uint256 _amount) private {
        globalShortSizes[_token] = globalShortSizes[_token].add(_amount);

        uint256 maxSize = _tokenConfigs.tokenConfigs[_token].maxGlobalShortSize;
        if (maxSize != 0) {
            _validate(
                globalShortSizes[_token] <= maxSize,
                Errors.V_MAX_SHORTS_EXCEEDED
            );
        }
    }

    function _decreaseGlobalShortSize(address _token, uint256 _amount) private {
        uint256 size = globalShortSizes[_token];
        if (_amount > size) {
            globalShortSizes[_token] = 0;
            return;
        }

        globalShortSizes[_token] = size.sub(_amount);
    }

    // we have this validation as a function instead of a modifier to reduce contract size
    function _validateManager() private view {
        _validate(
            msg.sender == addressesProvider.getPhlpManager(),
            Errors.V_NOT_PHLP_MANAGER
        );
    }

    function _validateConfigurator() private view {
        _validate(
            msg.sender == addressesProvider.getVaultConfigurator(),
            Errors.V_NOT_CONFIGURATOR
        );
    }

    function _validateRouter() private view {
        _validate(
            msg.sender == addressesProvider.getRouter(),
            Errors.V_NOT_ROUTER
        );
    }

    function _validate(bool _condition, uint256 _errorCode) private pure {
        GeneralUtils.validate(_condition, _errorCode);
    }
}
        

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{"contracts/protocol/libraries/utils/VaultUtils.sol":{"VaultUtils":"0x686285827f67f13b68baa45c8aa920997f877a0a"},"contracts/protocol/libraries/utils/GeneralUtils.sol":{"GeneralUtils":"0x0ef7e7d6944bb4d8c710f2418c75d8881174f4fd"},"contracts/protocol/libraries/logic/TokenConfigsLogic.sol":{"TokenConfigsLogic":"0x08858b5ca8ffc1a28c5645a8839f48641801660d"}},"evmVersion":"istanbul"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"addressesProvider_","internalType":"contract IAddressesProvider"}]},{"type":"event","name":"BuyUSDPH","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"tokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"usdphAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeBps","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClosePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateral","internalType":"uint256","indexed":false},{"type":"uint256","name":"averagePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"entryFundingRate","internalType":"uint256","indexed":false},{"type":"uint256","name":"reserveAmount","internalType":"uint256","indexed":false},{"type":"int256","name":"realisedPnl","internalType":"int256","indexed":false}],"anonymous":false},{"type":"event","name":"CollectMarginFees","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"feeUsd","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeTokens","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CollectSwapFees","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"feeUsd","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeTokens","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DecreaseGuaranteedUsd","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DecreasePoolAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DecreasePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DecreaseReservedAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DecreaseUsdphAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DirectPoolDeposit","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncreaseGuaranteedUsd","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncreasePoolAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncreasePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncreaseReservedAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncreaseUsdphAmount","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidatePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateral","internalType":"uint256","indexed":false},{"type":"uint256","name":"reserveAmount","internalType":"uint256","indexed":false},{"type":"int256","name":"realisedPnl","internalType":"int256","indexed":false},{"type":"uint256","name":"markPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PayLpFees","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"feeTokens","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SellUSDPH","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"usdphAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"tokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeBps","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Swap","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"address","name":"tokenIn","internalType":"address","indexed":false},{"type":"address","name":"tokenOut","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountOutAfterFees","internalType":"uint256","indexed":false},{"type":"uint256","name":"feeBps","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateFundingRate","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"fundingRate","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdatePnl","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"bool","name":"hasProfit","internalType":"bool","indexed":false},{"type":"uint256","name":"delta","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdatePosition","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"uint256","name":"size","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateral","internalType":"uint256","indexed":false},{"type":"uint256","name":"averagePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"entryFundingRate","internalType":"uint256","indexed":false},{"type":"uint256","name":"reserveAmount","internalType":"uint256","indexed":false},{"type":"int256","name":"realisedPnl","internalType":"int256","indexed":false},{"type":"uint256","name":"markPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BASIS_POINTS_DIVISOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"FUNDING_RATE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PRICE_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"USDPH_DECIMALS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAddressesProvider"}],"name":"addressesProvider","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"adjustForDecimals","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"address","name":"_tokenDiv","internalType":"address"},{"type":"address","name":"_tokenMul","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"allWhitelistedTokens","inputs":[{"type":"uint256","name":"i","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allWhitelistedTokensLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"buyUSDPH","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"buyUSDPHwithoutFee","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"clearTokenConfig","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cumulativeFundingRates","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"decreasePosition","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_collateralDelta","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"directPoolDeposit","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeReserves","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDelta","inputs":[{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_averagePrice","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_lastIncreasedTime","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getEntryFundingRate","inputs":[{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFeeBps","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphDelta","internalType":"uint256"},{"type":"uint256","name":"_feeBps","internalType":"uint256"},{"type":"uint256","name":"_taxBps","internalType":"uint256"},{"type":"bool","name":"_increment","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getFundingFee","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_entryFundingRate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNextAveragePrice","inputs":[{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_size","internalType":"uint256"},{"type":"uint256","name":"_averagePrice","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_nextPrice","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"uint256","name":"_lastIncreasedTime","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNextFundingRate","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPosition","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRedemptionAmount","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_usdphAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRedemptionCollateral","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRedemptionCollateralUsd","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct DataTypes.TokenConfig","components":[{"type":"bool","name":"isWhitelisted","internalType":"bool"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"weight","internalType":"uint256"},{"type":"uint256","name":"minProfitBps","internalType":"uint256"},{"type":"uint256","name":"maxUsdphAmount","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isShortable","internalType":"bool"},{"type":"uint256","name":"bufferAmount","internalType":"uint256"},{"type":"uint256","name":"maxGlobalShortSize","internalType":"uint256"}]}],"name":"getTokenConfig","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct DataTypes.VaultConfig","components":[{"type":"bool","name":"isSwapEnabled","internalType":"bool"},{"type":"bool","name":"isLeverageEnabled","internalType":"bool"},{"type":"uint256","name":"maxLeverage","internalType":"uint256"},{"type":"uint256","name":"taxBps","internalType":"uint256"},{"type":"uint256","name":"stableTaxBps","internalType":"uint256"},{"type":"uint256","name":"mintBurnFeeBps","internalType":"uint256"},{"type":"uint256","name":"swapFeeBps","internalType":"uint256"},{"type":"uint256","name":"stableSwapFeeBps","internalType":"uint256"},{"type":"uint256","name":"marginFeeBps","internalType":"uint256"},{"type":"uint256","name":"liquidationFeeUsd","internalType":"uint256"},{"type":"uint256","name":"minProfitTime","internalType":"uint256"},{"type":"bool","name":"hasDynamicFees","internalType":"bool"},{"type":"uint256","name":"stakingBps","internalType":"uint256"},{"type":"uint256","name":"fundingInterval","internalType":"uint256"},{"type":"uint256","name":"fundingRateFactor","internalType":"uint256"},{"type":"uint256","name":"stableFundingRateFactor","internalType":"uint256"}]}],"name":"getVaultConfig","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"globalShortSizes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"guaranteedUsd","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"increasePosition","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastFundingTimes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"liquidatePosition","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"address","name":"_feeReceiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolAmounts","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"collateral","internalType":"uint256"},{"type":"uint256","name":"averagePrice","internalType":"uint256"},{"type":"uint256","name":"entryFundingRate","internalType":"uint256"},{"type":"uint256","name":"reserveAmount","internalType":"uint256"},{"type":"int256","name":"realisedPnl","internalType":"int256"},{"type":"uint256","name":"lastIncreasedTime","internalType":"uint256"}],"name":"positions","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reservedAmounts","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"sellUSDPH","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTokenConfig","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"tuple","name":"tokenConfig","internalType":"struct DataTypes.TokenConfig","components":[{"type":"bool","name":"isWhitelisted","internalType":"bool"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint256","name":"weight","internalType":"uint256"},{"type":"uint256","name":"minProfitBps","internalType":"uint256"},{"type":"uint256","name":"maxUsdphAmount","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isShortable","internalType":"bool"},{"type":"uint256","name":"bufferAmount","internalType":"uint256"},{"type":"uint256","name":"maxGlobalShortSize","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setUsdphAmount","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVaultConfig","inputs":[{"type":"tuple","name":"vaultConfig","internalType":"struct DataTypes.VaultConfig","components":[{"type":"bool","name":"isSwapEnabled","internalType":"bool"},{"type":"bool","name":"isLeverageEnabled","internalType":"bool"},{"type":"uint256","name":"maxLeverage","internalType":"uint256"},{"type":"uint256","name":"taxBps","internalType":"uint256"},{"type":"uint256","name":"stableTaxBps","internalType":"uint256"},{"type":"uint256","name":"mintBurnFeeBps","internalType":"uint256"},{"type":"uint256","name":"swapFeeBps","internalType":"uint256"},{"type":"uint256","name":"stableSwapFeeBps","internalType":"uint256"},{"type":"uint256","name":"marginFeeBps","internalType":"uint256"},{"type":"uint256","name":"liquidationFeeUsd","internalType":"uint256"},{"type":"uint256","name":"minProfitTime","internalType":"uint256"},{"type":"bool","name":"hasDynamicFees","internalType":"bool"},{"type":"uint256","name":"stakingBps","internalType":"uint256"},{"type":"uint256","name":"fundingInterval","internalType":"uint256"},{"type":"uint256","name":"fundingRateFactor","internalType":"uint256"},{"type":"uint256","name":"stableFundingRateFactor","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"swap","inputs":[{"type":"address","name":"_tokenIn","internalType":"address"},{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenBalances","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenToUsdMin","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalTokenWeights","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateCumulativeFundingRate","inputs":[{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"usdphAmounts","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"validateLiquidation","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"bool","name":"_raise","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawFees","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]}]
              

Contract Creation Code

Verify & Publish
0x60a06040523480156200001157600080fd5b5060405162005d0338038062005d0383398101604081905262000034916200004f565b600160005560601b6001600160601b0319166080526200007f565b60006020828403121562000061578081fd5b81516001600160a01b038116811462000078578182fd5b9392505050565b60805160601c615bda62000129600039806106ed52806108a852806109625280610c2c5280610d5f5280610e0252806110a452806115b552806117c252806118e45280611a065280611ac05280611c3a5280611f4c52806120fe52806122d95280612388528061253752806127c4528061289e5280612ad95280612d1a5280613248528061359f5280613846528061395b5280613b26528061423552806144155250615bda6000f3fe608060405234801561001057600080fd5b50600436106102955760003560e01c8063843d439911610167578063cb67e3b1116100ce578063de2ea94811610087578063de2ea948146105cf578063e468baf0146105e2578063e67f59a7146105f5578063f07456ce14610608578063f25552781461061b578063fbfded6d1461062e57610295565b8063cb67e3b11461054d578063d54d5a9f1461056d578063d8f897c31461058e578063da76524c146105a1578063db97495f146105b4578063dc8f5fac146105c757610295565b8063b136ca4911610120578063b136ca49146104d7578063b1cc53ab146104ea578063b2a2353e146104fd578063c3c7b9e914610512578063c65bc7b114610525578063c72c4d101461053857610295565b8063843d43991461047057806389dea1dc146104835780638a78daa81461049657806393316212146104a957806395082d25146104bc578063a93acac2146104c457610295565b806342e851821161020b5780635bae4263116101c45780635bae4263146103fb5780635c07eaab1461040e5780635da69ed71461042f5780635f7bc119146104425780636be6026b1461045557806382a084901461045d57610295565b806342e851821461036257806348d91abf146103755780634a3f088d14610388578063514ea4bf146103af578063523fba7f146103d557806352f55eed146103e857610295565b80631ce9cb8f1161025d5780631ce9cb8f146102f057806320355a2c1461030357806328a32d5c1461031657806329ff9615146103295780632c668ec11461033c578063421528731461034f57610295565b806303563e671461029a5780630754d4fb146102b85780630842b076146102cd5780630a48d5a9146102d5578063126082cf146102e8575b600080fd5b6102a2610641565b6040516102af91906159bc565b60405180910390f35b6102cb6102c636600461513c565b610646565b005b6102a26106a1565b6102a26102e336600461513c565b6106a7565b6102a2610810565b6102a26102fe366004614d8c565b610816565b6102a2610311366004614d8c565b610828565b6102cb6103243660046150fb565b610b98565b6102a2610337366004614d8c565b610c10565b6102a261034a36600461513c565b610c27565b6102a261035d3660046152f4565b610dfd565b6102a2610370366004614d8c565b610f3f565b6102cb610383366004614fe0565b610f51565b61039b610396366004614e46565b6113ea565b6040516102af9897969594939291906159d3565b6103c26103bd3660046152ac565b6114d4565b6040516102af979695949392919061553e565b6102a26103e3366004614d8c565b611511565b6102a26103f6366004614d8c565b611523565b6102a2610409366004614dc4565b611535565b61042161041c366004615167565b6118c5565b6040516102af929190615476565b6102a261043d366004614dc4565b611986565b6102cb610450366004614d8c565b611dc6565b6102a2611e9e565b6102a261046b366004615039565b611ea5565b6102a261047e36600461521c565b611f1a565b6102cb6104913660046152c4565b611fd8565b6102a26104a4366004614d8c565b611fed565b6102a26104b7366004614dfc565b611fff565b6102a26124f7565b6102a26104d2366004614d8c565b612507565b6102a26104e5366004614d8c565b6125b1565b6102a26104f83660046150bc565b612656565b6105056126ee565b6040516102af91906158ed565b6102a2610520366004614d8c565b61279e565b6102a2610533366004614d8c565b6127b0565b6105406127c2565b6040516102af9190615381565b61056061055b366004614d8c565b6127e6565b6040516102af9190615795565b61058061057b366004614f11565b61287f565b6040516102af9291906159c5565b6102a261059c366004614d8c565b612932565b6102a26105af366004614f73565b612944565b6102a26105c23660046151b8565b6129e5565b6102a2612a76565b6102cb6105dd366004614ea1565b612a7c565b6105406105f03660046152ac565b612f5b565b6102cb610603366004614d8c565b612f88565b6102a2610616366004614d8c565b612ffd565b6102a2610629366004614dc4565b61300f565b6102cb61063c366004614dc4565b613065565b601281565b61064e613243565b6001600160a01b03821660009081526014602052604090205480821115610688576106828361067d84846132f4565b613351565b5061069d565b61069b8361069683856132f4565b613407565b505b5050565b60115490565b6000816106b65750600061080a565b61080760106002016000856001600160a01b03166001600160a01b0316815260200190815260200160002060010154600a0a6108017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561074457600080fd5b505afa158015610758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077c9190614da8565b6001600160a01b03166376d697608760006040518363ffffffff1660e01b81526004016107aa92919061543a565b60206040518083038186803b1580156107c257600080fd5b505afa1580156107d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fa91906152dc565b85906134da565b90613533565b90505b92915050565b61271081565b601b6020526000908152604090205481565b600060026000541415610870576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005561087d61359a565b6001600160a01b0382166000908152601260205260409020546108a49060ff16600e613645565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190614da8565b905060006109448461367e565b905061095460008211600f613645565b61095e8485613065565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156109b957600080fd5b505afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f19190614da8565b6001600160a01b03166376d697608660006040518363ffffffff1660e01b8152600401610a1f92919061543a565b60206040518083038186803b158015610a3757600080fd5b505afa158015610a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6f91906152dc565b90506000610a8d68327cb2734119d3b7a9601e1b61080185856134da565b9050610a9a818786610dfd565b9050610aaa600082116012613645565b6000610ac668327cb2734119d3b7a9601e1b61080186866134da565b9050610ad3818887610dfd565b9050610adf8782613351565b610ae98785613736565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990610b1790339085906004016153c6565b600060405180830381600087803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b505050507fc6c8b444f53d4e65122f6f9780fd7db1ff1a47d82ff0cbb2f450eee0c289e534338886846000604051610b81959493929190615395565b60405180910390a160016000559695505050505050565b610ba0613243565b6040516326286a1760e21b81527308858b5ca8ffc1a28c5645a8839f48641801660d906398a1a85c90610bdc9060109086908690600401615845565b60006040518083038186803b158015610bf457600080fd5b505af4158015610c08573d6000803e3d6000fd5b505050505050565b6000610c1f826102e3846125b1565b90505b919050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015610c8357600080fd5b505afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb9190614da8565b6001600160a01b03166376d697608560016040518363ffffffff1660e01b8152600401610ce992919061543a565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3991906152dc565b90506000610d57826108018668327cb2734119d3b7a9601e1b6134da565b9050610df4817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610db657600080fd5b505afa158015610dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dee9190614da8565b87610dfd565b95945050505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5957600080fd5b505afa158015610e6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e919190614da8565b90506000816001600160a01b0316856001600160a01b031614610ecf576001600160a01b038516600090815260126020526040902060010154610ed2565b60125b90506000826001600160a01b0316856001600160a01b031614610f10576001600160a01b038516600090815260126020526040902060010154610f13565b60125b9050610f3282600a0a61080183600a0a8a6134da90919063ffffffff16565b93505050505b9392505050565b60146020526000908152604090205481565b60026000541415610f97576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600055610fa4613841565b604051634755223960e01b81527308858b5ca8ffc1a28c5645a8839f48641801660d90634755223990610fe29060109088908890879060040161581e565b60006040518083038186803b158015610ffa57600080fd5b505af415801561100e573d6000803e3d6000fd5b5050600154604080518082019091526002815261064760f31b60208201529250610100900460ff16905061105e5760405162461bcd60e51b81526004016110559190615742565b60405180910390fd5b506110698484613065565b6000611077868686856138f0565b6000818152601a602090815260408083208151631f94a27560e31b81529151949550936001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263fca513a89260048082019391829003018186803b1580156110e657600080fd5b505afa1580156110fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111e9190614da8565b6001600160a01b03166376d6976087866040518363ffffffff1660e01b815260040161114b92919061543a565b60206040518083038186803b15801561116357600080fd5b505afa158015611177573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119b91906152dc565b82549091506111ac57600282018190555b8154158015906111bc5750600085115b156111e2576111dc868360000154846002015487858a88600601546129e5565b60028301555b6000806111fc8a8a8a898b89600001548a60030154613929565b91509150600061120b8a61367e565b905060006112198b836106a7565b600187015490915061122b9082613a94565b6001870181905561124090851115601d613645565b600186015461124f90856132f4565b600187015561125f8b8b8a612656565b60038701558554611270908a613a94565b808755426006880155611286901515601e613645565b61129886600001548760010154613aee565b6112a68c8c8c8b600161287f565b505060006112b68c8b6001613b12565b60048801549091506112c89082613a94565b60048801556112d78c82613c5d565b881561131e576112f08c6112eb8c88613a94565b613cf2565b6112fa8c83613d63565b6113048c84613736565b6113198c6113148e886000613b12565b613dd4565b611328565b6113288b8b613e5b565b7f2fe68525253654c21998f35787a8d0f361905ef647c854092430ab65f2f15022888e8e8e868f8f8d8d604051611367999897969594939291906154da565b60405180910390a17f20853733b590dce729d9f4628682ebd9a34d2354e72679e66f43a008fc03b77388886000015489600101548a600201548b600301548c600401548d600501548d6040516113c498979695949392919061556e565b60405180910390a16113d68c85613ed3565b505060016000555050505050505050505050565b6000806000806000806000806000601a60006114088f8f8f8f6138f0565b81526020019081526020016000206040518060e001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090506000808260a0015113611483578160a00151600003611489565b8160a001515b9050816000015182602001518360400151846060015185608001518560008860a0015112158860c0015199509950995099509950995099509950505094995094995094999196509450565b601a602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b60136020526000908152604090205481565b60156020526000908152604090205481565b60006002600054141561157d576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005561158a61359a565b6001600160a01b0383166000908152601260205260409020546115b19060ff16600e613645565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561160c57600080fd5b505afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116449190614da8565b905060006116518261367e565b9050611661600082116012613645565b61166b8586613065565b60006116778683610c27565b9050611687600082116015613645565b6116918683613407565b61169b8682613dd4565b604051632770a7eb60e21b81526001600160a01b03841690639dc29fac906116c990309086906004016153c6565b600060405180830381600087803b1580156116e357600080fd5b505af11580156116f7573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b03861692506370a082319150611727903090600401615381565b60206040518083038186803b15801561173f57600080fd5b505afa158015611753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177791906152dc565b6001600160a01b03841660009081526013602052604080822092909255905163562b7e0760e11b815273686285827f67f13b68baa45c8aa920997f877a0a9063ac56fc0e906117ee907f0000000000000000000000000000000000000000000000000000000000000000908b908890600401615642565b60206040518083038186803b15801561180657600080fd5b505af415801561181a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183e91906152dc565b905060008061184e898585613fa0565b91509150611860600083116016613645565b61186b89838a61405b565b7ff0769e076d0b71b7205e1d6800e3ede98265f5a21bacbd6067947cbe7a3fa671888a8785876040516118a2959493929190615395565b60405180910390a16118b48982613ed3565b506001600055979650505050505050565b60008073686285827f67f13b68baa45c8aa920997f877a0a63cfb90b207f000000000000000000000000000000000000000000000000000000000000000089898989896040518763ffffffff1660e01b815260040161192996959493929190615666565b604080518083038186803b15801561194057600080fd5b505af4158015611954573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611978919061527f565b915091509550959350505050565b6000600260005414156119ce576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b60026000556119db61359a565b6001600160a01b038316600090815260126020526040902054611a029060ff16600e613645565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a5d57600080fd5b505afa158015611a71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a959190614da8565b90506000611aa28561367e565b9050611ab260008211600f613645565b611abc8586613065565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1757600080fd5b505afa158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614da8565b6001600160a01b03166376d697608760006040518363ffffffff1660e01b8152600401611b7d92919061543a565b60206040518083038186803b158015611b9557600080fd5b505afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd91906152dc565b90506000611beb68327cb2734119d3b7a9601e1b61080185856134da565b9050611bf8818886610dfd565b9050611c08600082116012613645565b6040516360d41f1560e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063c1a83e2a90611c66907f0000000000000000000000000000000000000000000000000000000000000000908c908790600401615642565b60206040518083038186803b158015611c7e57600080fd5b505af4158015611c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb691906152dc565b9050600080611cc68a8785613fa0565b90925090506000611ce768327cb2734119d3b7a9601e1b61080185896134da565b9050611cf4818c8a610dfd565b9050611d008b82613351565b611d0a8b84613736565b6040516340c10f1960e01b81526001600160a01b038916906340c10f1990611d38908d9085906004016153c6565b600060405180830381600087803b158015611d5257600080fd5b505af1158015611d66573d6000803e3d6000fd5b505050507fc6c8b444f53d4e65122f6f9780fd7db1ff1a47d82ff0cbb2f450eee0c289e5348a8c898488604051611da1959493929190615395565b60405180910390a1611db38b83613ed3565b60016000559a9950505050505050505050565b60026000541415611e0c576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260009081556001600160a01b038216815260126020526040902054611e379060ff16600e613645565b6000611e428261367e565b9050611e5260008211600f613645565b611e5c8282613736565b7fa5a389190ebf6170a133bda5c769b77f4d6715b8aa172ec0ddf8473d0b4944bd8282604051611e8d9291906153c6565b60405180910390a150506001600055565b620f424081565b600060026000541415611eed576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600055611efa613841565b611f098888888888888861410c565b600160005598975050505050505050565b6040516308e83b0160e21b815260009073686285827f67f13b68baa45c8aa920997f877a0a906323a0ec0490611f7e907f0000000000000000000000000000000000000000000000000000000000000000908a908a908a908a908a9060040161569e565b60206040518083038186803b158015611f9657600080fd5b505af4158015611faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fce91906152dc565b9695505050505050565b611fe0613243565b80600161069b8282615a2d565b601c6020526000908152604090205481565b600060026000541415612047576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005560015461205d9060ff166017613645565b6001600160a01b0384166000908152601260205260409020546120849060ff16600e613645565b6001600160a01b0383166000908152601260205260409020546120ab9060ff16600e613645565b6120cb836001600160a01b0316856001600160a01b03161415601a613645565b6120d58485613065565b6120df8384613065565b60006120ea8561367e565b90506120fa60008211601b613645565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561215557600080fd5b505afa158015612169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218d9190614da8565b90506000816001600160a01b03166376d697608860006040518363ffffffff1660e01b81526004016121c092919061543a565b60206040518083038186803b1580156121d857600080fd5b505afa1580156121ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221091906152dc565b90506000826001600160a01b03166376d697608860016040518363ffffffff1660e01b815260040161224392919061543a565b60206040518083038186803b15801561225b57600080fd5b505afa15801561226f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229391906152dc565b905060006122a58261080187866134da565b90506122b2818a8a610dfd565b905060006122d068327cb2734119d3b7a9601e1b61080188876134da565b9050612368818b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561233057600080fd5b505afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d9190614da8565b9050600073686285827f67f13b68baa45c8aa920997f877a0a6387e35c2c7f00000000000000000000000000000000000000000000000000000000000000008d8d866040518563ffffffff1660e01b81526004016123c99493929190615618565b60206040518083038186803b1580156123e157600080fd5b505af41580156123f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241991906152dc565b90506000806124298c8685613fa0565b915091506124378d85613351565b6124418c85613407565b61244b8d8a613736565b6124558c86613dd4565b6001600160a01b038c1660009081526012602090815260408083206006015460159092529091205461248a9111156064613645565b6124958c838d61405b565b7f0874b2d545cb271cdbda4e093020c452328b24af12382ed62c4d00f5c26709db8b8e8e8c8987896040516124d097969594939291906153f9565b60405180910390a16124e28c82613ed3565b5060016000559b9a5050505050505050505050565b68327cb2734119d3b7a9601e1b81565b6040516246b9f360e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a90628d73e690612561907f00000000000000000000000000000000000000000000000000000000000000009086906004016153df565b60206040518083038186803b15801561257957600080fd5b505af415801561258d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f91906152dc565b6001600160a01b03811660009081526012602052604081206005015460ff16156125f457506001600160a01b038116600090815260156020526040902054610c22565b6001600160a01b03821660009081526017602052604081205461261990849083613b12565b6001600160a01b038416600090815260166020908152604080832054601590925290912054919250610f3891612650908490613a94565b906132f4565b60405163429a429f60e01b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063429a429f90612696903090889088908890600401615718565b60206040518083038186803b1580156126ae57600080fd5b505af41580156126c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e691906152dc565b949350505050565b6126f6614cac565b50604080516102008101825260015460ff8082161515835261010091829004811615156020840152600254938301939093526003546060830152600454608083015260055460a083015260065460c083015260075460e083015260085490820152600954610120820152600a54610140820152600b549091161515610160820152600c54610180820152600d546101a0820152600e546101c0820152600f546101e082015290565b60166020526000908152604090205481565b60186020526000908152604090205481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6127ee614d2f565b506001600160a01b0316600090815260126020908152604091829020825161012081018452815460ff9081161515825260018301549382019390935260028201549381019390935260038101546060840152600481015460808401526005810154808316151560a085015261010090819004909216151560c0840152600681015460e0840152600701549082015290565b60008073686285827f67f13b68baa45c8aa920997f877a0a634e9c91757f000000000000000000000000000000000000000000000000000000000000000089898989896040518763ffffffff1660e01b81526004016128e3969594939291906155a4565b604080518083038186803b1580156128fa57600080fd5b505af415801561290e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611978919061531a565b60196020526000908152604090205481565b604051636df5632b60e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063dbeac6569061298a9030908b908b908b908b908b908b906004016156d4565b60206040518083038186803b1580156129a257600080fd5b505af41580156129b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129da91906152dc565b979650505050505050565b60008060006129f78a8a8a8a886118c5565b90925090506000612a088a87613a94565b905060008815612a375783612a2657612a2182846132f4565b612a30565b612a308284613a94565b9050612a58565b83612a4b57612a468284613a94565b612a55565b612a5582846132f4565b90505b612a66816108018a856134da565b9c9b505050505050505050505050565b60105490565b60026000541415612ac2576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600081905550612b79336001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b3057600080fd5b505afa158015612b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b689190614da8565b6001600160a01b0316146022613645565b612b838484613065565b6000612b91868686866138f0565b6000818152601a6020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015291925090612c00901515601f613645565b600080612c1189898989600061287f565b91509150612c2482600014156024613645565b8160021415612c4b57612c41898989600087600001518b8f61410c565b5050505050612f4f565b6000612c5989836000613b12565b6001600160a01b038a166000908152601b6020526040902054909150612c7f9082613a94565b6001600160a01b038a166000908152601b60205260409081902091909155517f5d0c0019d3d45fadeb74eff9d2c9924d146d000ac6bcf3c28bf0ac3c9baa011a90612ccf908b9085908590615455565b60405180910390a1612ce589856080015161466f565b8615612d165760208401518451612d06918b91612d01916132f4565b613d63565b612d16896113148b856000613b12565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7157600080fd5b505afa158015612d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da99190614da8565b6001600160a01b03166376d697608a8a156040518363ffffffff1660e01b8152600401612dd792919061543a565b60206040518083038186803b158015612def57600080fd5b505afa158015612e03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2791906152dc565b90507f2e1f85a64a2f22cf2f0c42584e7c919ed4abe8d53675cff0f62bf1e95a1c676f868c8c8c8c8a600001518b602001518c608001518d60a001518a604051612e7a9a99989796959493929190615486565b60405180910390a187158015612e935750846020015183105b15612ec3576020850151600090612eaa90856132f4565b9050612ec18b612ebc8d846000613b12565b613736565b505b87612ed657612ed6898660000151614718565b6000868152601a60205260408120818155600181018290556002810182905560038101829055600481018290556005810182905560060181905560095490612f27908c906113149082908590613b12565b612f3d8b612f378d846000613b12565b8a61405b565b612f478b84613ed3565b505050505050505b50506001600055505050565b600060106001018281548110612f6d57fe5b6000918252602090912001546001600160a01b031692915050565b612f90613243565b604051632e43d10160e01b81527308858b5ca8ffc1a28c5645a8839f48641801660d90632e43d10190612fca906010908590600401615807565b60006040518083038186803b158015612fe257600080fd5b505af4158015612ff6573d6000803e3d6000fd5b5050505050565b60176020526000908152604090205481565b600061301961359a565b6001600160a01b0383166000908152601b60205260409020548061304157600091505061080a565b6001600160a01b0384166000908152601b602052604081205561080784828561405b565b60405163fbfded6d60e01b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063fbfded6d906130a190869086906004016153df565b60206040518083038186803b1580156130b957600080fd5b505af41580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f19190615263565b9050806130fe575061069d565b600d546001600160a01b038416600090815260196020526040902054613153576131328161312c4282613533565b906134da565b6001600160a01b0385166000908152601960205260409020555061069d9050565b6001600160a01b03841660009081526019602052604090205442906131789083613a94565b111561318557505061069d565b600061319085612507565b6001600160a01b0386166000908152601860205260409020549091506131b69082613a94565b6001600160a01b0386166000908152601860205260409020556131dd8261312c4282613533565b6001600160a01b038616600090815260196020908152604080832093909355601890528190205490517fa146fc154e1913322e9817d49f0d5c37466c24326e15de10e739a948be815eab91613234918891906153c6565b60405180910390a15050505050565b6132f27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561329f57600080fd5b505afa1580156132b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d79190614da8565b6001600160a01b0316336001600160a01b0316146066613645565b565b60008282111561334b576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b0382166000908152601460205260409020546133749082613a94565b6001600160a01b03831660009081526014602090815260408083209390935560129052206004015480156133c9576001600160a01b0383166000908152601460205260409020546133c9908210156033613645565b7ffbf914421322be849bbd116e701fe46b8e6b903e15192c1d479b8748a738452083836040516133fa9291906153c6565b60405180910390a1505050565b6001600160a01b038216600090815260146020526040902054818111613482576001600160a01b03831660009081526014602052604080822091909155517fda43d5cdf64be33afb6f3e9858581d78f3855a1f6fcb50e5eb86c0c5db312d1c9061347490859084906153c6565b60405180910390a15061069d565b61348c81836132f4565b6001600160a01b0384166000908152601460205260409081902091909155517fda43d5cdf64be33afb6f3e9858581d78f3855a1f6fcb50e5eb86c0c5db312d1c906133fa90859085906153c6565b6000826134e95750600061080a565b828202828482816134f657fe5b04146108075760405162461bcd60e51b8152600401808060200182810382526021815260200180615b5a6021913960400191505060405180910390fd5b6000808211613589576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161359257fe5b049392505050565b6132f27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663028d27d86040518163ffffffff1660e01b815260040160206040518083038186803b1580156135f657600080fd5b505afa15801561360a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362e9190614da8565b6001600160a01b0316336001600160a01b03161460365b60405163cda9d28760e01b8152730ef7e7d6944bb4d8c710f2418c75d8881174f4fd9063cda9d28790610bdc9085908590600401615476565b6001600160a01b0381166000818152601360205260408082205490516370a0823160e01b8152919290918391906370a08231906136bf903090600401615381565b60206040518083038186803b1580156136d757600080fd5b505afa1580156136eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061370f91906152dc565b6001600160a01b038516600090815260136020526040902081905590506126e681836132f4565b6001600160a01b0382166000908152601560205260409020546137599082613a94565b6001600160a01b0383166000818152601560205260408082209390935591516370a0823160e01b81526370a0823190613796903090600401615381565b60206040518083038186803b1580156137ae57600080fd5b505afa1580156137c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e691906152dc565b6001600160a01b038416600090815260156020526040902054909150613810908210156031613645565b7f976177fbe09a15e5e43f848844963a42b41ef919ef17ff21a17a5421de8f473783836040516133fa9291906153c6565b6132f27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b15801561389d57600080fd5b505afa1580156138b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d59190614da8565b6001600160a01b0316336001600160a01b0316146067613645565b6000848484846040516020016139099493929190615343565b604051602081830303815290604052805190602001209050949350505050565b60008060006139f661393f8b8b8b8b8a8a612944565b73686285827f67f13b68baa45c8aa920997f877a0a63d4b9aa637f00000000000000000000000000000000000000000000000000000000000000008e8e8e8e8e6040518763ffffffff1660e01b81526004016139a0969594939291906155de565b60206040518083038186803b1580156139b857600080fd5b505af41580156139cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f091906152dc565b90613a94565b90506000613a068a836000613b12565b6001600160a01b038b166000908152601b6020526040902054909150613a2c9082613a94565b6001600160a01b038b166000908152601b60205260409081902091909155517f5d0c0019d3d45fadeb74eff9d2c9924d146d000ac6bcf3c28bf0ac3c9baa011a90613a7c908c9085908590615455565b60405180910390a1909a909950975050505050505050565b600082820183811015610807576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b81613b0457613aff81156027613645565b61069d565b61069d818310156028613645565b600082613b2157506000610f38565b6126e67f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015613b7d57600080fd5b505afa158015613b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb59190614da8565b6001600160a01b03166376d697608685156040518363ffffffff1660e01b8152600401613be392919061543a565b60206040518083038186803b158015613bfb57600080fd5b505afa158015613c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3391906152dc565b6001600160a01b038616600090815260126020526040902060010154610801908690600a0a6134da565b6001600160a01b038216600090815260166020526040902054613c809082613a94565b6001600160a01b038316600090815260166020818152604080842085905560158252909220549152613cb59111156032613645565b7faa5649d82f5462be9d19b0f2b31a59b2259950a6076550bac9f3a1c07db9f66d8282604051613ce69291906153c6565b60405180910390a15050565b6001600160a01b038216600090815260176020526040902054613d159082613a94565b6001600160a01b0383166000908152601760205260409081902091909155517fd9d4761f75e0d0103b5cbeab941eeb443d7a56a35b5baf2a0787c03f03f4e47490613ce690849084906153c6565b6001600160a01b038216600090815260176020526040902054613d8690826132f4565b6001600160a01b0383166000908152601760205260409081902091909155517f34e07158b9db50df5613e591c44ea2ebc82834eff4a4dc3a46e000e608261d6890613ce690849084906153c6565b6001600160a01b038216600090815260156020526040902054613df790826132f4565b6001600160a01b03831660009081526015602090815260408083208490556016909152902054613e2a9110156032613645565b7f112726233fbeaeed0f5b1dba5cb0b2b81883dee49fb35ff99fd98ed9f6d31eb08282604051613ce69291906153c6565b6001600160a01b0382166000908152601c6020526040902054613e7e9082613a94565b6001600160a01b0383166000908152601c6020908152604080832093909355601290522060070154801561069b576001600160a01b0383166000908152601c602052604090205461069b908210156065613645565b6000613ef86127106108016107fa6001600b01546127106132f490919063ffffffff16565b9050801561069b576001600160a01b0383166000908152601b6020526040902054613f2390826132f4565b6001600160a01b0384166000908152601b6020908152604080832093909355601590522054613f529082613a94565b6001600160a01b0384166000908152601560205260409081902091909155517fe1f042ea063a41fdab4bcdfa4b5e9036c3444aead3f6e901aa5073a9f72e8abd906133fa90859084906153c6565b60008080613fbe612710610801613fb782886132f4565b88906134da565b90506000613fcc86836132f4565b6001600160a01b0388166000908152601b6020526040902054909150613ff29082613a94565b6001600160a01b0388166000908152601b60205260409020557f47cd9dda0e50ce30bcaaacd0488452b596221c07ac402a581cfae4d3933cac2b8761403781846106a7565b8360405161404793929190615455565b60405180910390a190969095509350505050565b61406f6001600160a01b0384168284614780565b6040516370a0823160e01b81526001600160a01b038416906370a082319061409b903090600401615381565b60206040518083038186803b1580156140b357600080fd5b505afa1580156140c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140eb91906152dc565b6001600160a01b039093166000908152601360205260409020929092555050565b60006141188787613065565b6000614126898989876138f0565b6000818152601a60205260409020805491925090614147901515601f613645565b61415986826000015410156020613645565b61416b87826001015410156021613645565b60018101548154600483015460009161418891610801908b6134da565b600484015490915061419a90826132f4565b60048401556141a98b8261466f565b506000806141bb8d8d8d8d8d8d6147d2565b8554919350915089146143f7576141d38c8c8a612656565b600385015583546141e4908a6132f4565b80855560018501546141f69190613aee565b6142048d8d8d8b600161287f565b50508715614231576142278c6112eb8660010154866132f490919063ffffffff16565b6142318c8a613d63565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561428c57600080fd5b505afa1580156142a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c49190614da8565b6001600160a01b03166376d697608d8b156040518363ffffffff1660e01b81526004016142f292919061543a565b60206040518083038186803b15801561430a57600080fd5b505afa15801561431e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061434291906152dc565b90507f93d75d64d1f84fc6f430a64fc578bdd4c1e090e90ea2d51773e626d19de56d30868f8f8f8f8f8f886143778c8c6132f4565b60405161438c999897969594939291906154da565b60405180910390a17f20853733b590dce729d9f4628682ebd9a34d2354e72679e66f43a008fc03b7738686600001548760010154886002015489600301548a600401548b60050154886040516143e998979695949392919061556e565b60405180910390a150614609565b8715614411576144078c84613cf2565b6144118c8a613d63565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561446c57600080fd5b505afa158015614480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144a49190614da8565b6001600160a01b03166376d697608d8b156040518363ffffffff1660e01b81526004016144d292919061543a565b60206040518083038186803b1580156144ea57600080fd5b505afa1580156144fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452291906152dc565b90507f93d75d64d1f84fc6f430a64fc578bdd4c1e090e90ea2d51773e626d19de56d30868f8f8f8f8f8f886145578c8c6132f4565b60405161456c999897969594939291906154da565b60405180910390a17f73af1d417d82c240fdb6d319b34ad884487c6bf2845d98980cc52ad9171cb4558686600001548760010154886002015489600301548a600401548b600501546040516145c7979695949392919061553e565b60405180910390a1506000858152601a602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600601555b87614618576146188b8a614718565b811561465c578715614634576146348c6113148e856000613b12565b60006146428d836000613b12565b905061464f8d828a61405b565b95506129da945050505050565b5060009c9b505050505050505050505050565b604080518082018252601b81527f5661756c743a20696e73756666696369656e74207265736572766500000000006020808301919091526001600160a01b0385166000908152601690915291909120546146ca9183906149de565b6001600160a01b0383166000908152601660205260409081902091909155517f533cb5ed32be6a90284e96b5747a1bfc2d38fdb5768a6b5f67ff7d62144ed67b90613ce690849084906153c6565b6001600160a01b0382166000908152601c60205260409020548082111561475857506001600160a01b0382166000908152601c602052604081205561069d565b61476281836132f4565b6001600160a01b0384166000908152601c6020526040902055505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261069b908490614a75565b6000806000806000806147e78c8c8c8a6138f0565b9050601a6000828152602001908152602001600020935060008061481a8c876000015488600201548c8a600601546118c5565b87549196508693509150614832906108018c846134da565b93507f3ff41bdde87755b687ae83d0221a232b6be51a803330ed9661c1b5d0105e0d8a83868660405161486793929190615528565b60405180910390a150505060008061488c8d8d8d8b8d8a600001548b60030154613929565b91509150600084801561489f5750600084115b156148d157506005850180548401905582886148d15760006148c38e866000613b12565b90506148cf8e82613dd4565b505b841580156148df5750600084115b156149255760018601546148f390856132f4565b60018701558861491957600061490b8e866000613b12565b90506149178e82613736565b505b60058601805485900390555b8a1561494d57614935818c613a94565b6001870154909150614947908c6132f4565b60018701555b85548a1415614970576001860154614966908290613a94565b6000600188015590505b808381111561498a5761498382856132f4565b90506149c0565b600187015461499990856132f4565b600188015589156149c05760006149b28f866000613b12565b90506149be8f82613dd4565b505b6149ca8e84613ed3565b909e909d509b505050505050505050505050565b60008184841115614a6d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614a32578181015183820152602001614a1a565b50505050905090810190601f168015614a5f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000614aca826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b269092919063ffffffff16565b80519091501561069b57808060200190516020811015614ae957600080fd5b505161069b5760405162461bcd60e51b815260040180806020018281038252602a815260200180615b7b602a913960400191505060405180910390fd5b60606126e6848460008585614b3a85614c40565b614b8b576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310614bc95780518252601f199092019160209182019101614baa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614c2b576040519150601f19603f3d011682016040523d82523d6000602084013e614c30565b606091505b50915091506129da828286614c46565b3b151590565b60608315614c55575081610f38565b825115614c655782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315614a32578181015183820152602001614a1a565b604051806102000160405280600015158152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081525090565b6040518061012001604052806000151581526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160008152602001600081525090565b8035610c2281615b2b565b600060208284031215614d9d578081fd5b813561080781615b13565b600060208284031215614db9578081fd5b815161080781615b13565b60008060408385031215614dd6578081fd5b8235614de181615b13565b91506020830135614df181615b13565b809150509250929050565b600080600060608486031215614e10578081fd5b8335614e1b81615b13565b92506020840135614e2b81615b13565b91506040840135614e3b81615b13565b809150509250925092565b60008060008060808587031215614e5b578081fd5b8435614e6681615b13565b93506020850135614e7681615b13565b92506040850135614e8681615b13565b91506060850135614e9681615b2b565b939692955090935050565b600080600080600060a08688031215614eb8578081fd5b8535614ec381615b13565b94506020860135614ed381615b13565b93506040860135614ee381615b13565b92506060860135614ef381615b2b565b91506080860135614f0381615b13565b809150509295509295909350565b600080600080600060a08688031215614f28578081fd5b8535614f3381615b13565b94506020860135614f4381615b13565b93506040860135614f5381615b13565b92506060860135614f6381615b2b565b91506080860135614f0381615b2b565b60008060008060008060c08789031215614f8b578081fd5b8635614f9681615b13565b95506020870135614fa681615b13565b94506040870135614fb681615b13565b93506060870135614fc681615b2b565b9598949750929560808101359460a0909101359350915050565b600080600080600060a08688031215614ff7578081fd5b853561500281615b13565b9450602086013561501281615b13565b9350604086013561502281615b13565b9250606086013591506080860135614f0381615b2b565b600080600080600080600060e0888a031215615053578485fd5b873561505e81615b13565b9650602088013561506e81615b13565b9550604088013561507e81615b13565b9450606088013593506080880135925060a088013561509c81615b2b565b915060c08801356150ac81615b13565b8091505092959891949750929550565b6000806000606084860312156150d0578081fd5b83356150db81615b13565b925060208401356150eb81615b13565b91506040840135614e3b81615b2b565b60008082840361014081121561510f578283fd5b833561511a81615b13565b9250610120601f198201121561512e578182fd5b506020830190509250929050565b6000806040838503121561514e578182fd5b823561515981615b13565b946020939093013593505050565b600080600080600060a0868803121561517e578283fd5b853561518981615b13565b9450602086013593506040860135925060608601356151a781615b2b565b949793965091946080013592915050565b600080600080600080600060e0888a0312156151d2578081fd5b87356151dd81615b13565b9650602088013595506040880135945060608801356151fb81615b2b565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600060a08688031215615233578283fd5b853561523e81615b13565b94506020860135935060408601359250606086013591506080860135614f0381615b2b565b600060208284031215615274578081fd5b815161080781615b2b565b60008060408385031215615291578182fd5b825161529c81615b2b565b6020939093015192949293505050565b6000602082840312156152bd578081fd5b5035919050565b600061020082840312156152d6578081fd5b50919050565b6000602082840312156152ed578081fd5b5051919050565b600080600060608486031215615308578081fd5b833592506020840135614e2b81615b13565b6000806040838503121561532c578182fd5b505080516020909101519092909150565b15159052565b6bffffffffffffffffffffffff19606095861b8116825293851b841660148201529190931b909116602882015290151560f81b603c820152603d0190565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295871660208701529390951660408501526060840191909152608083015260a082019290925260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b9115158252602082015260400190565b998a526001600160a01b0398891660208b015296881660408a0152949096166060880152911515608087015260a086015260c085015260e08401929092526101008301919091526101208201526101400190565b9889526001600160a01b0397881660208a01529587166040890152939095166060870152608086019190915260a085015291151560c084015260e08301919091526101008201526101200190565b9283529015156020830152604082015260600190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152911515608082015290151560a082015260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152911515608082015260a081019190915260c00190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039687168152949095166020850152604084019290925260608301521515608082015260a081019190915260c00190565b6001600160a01b03968716815294909516602085015260408401929092526060830152608082015290151560a082015260c00190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152921515608083015260a082019290925260c081019190915260e00190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000602080835283518082850152825b8181101561576e57858101830151858201604001528201615752565b8181111561577f5783604083870101525b50601f01601f1916929092016040019392505050565b6000610120820190508251151582526020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151151560a083015260c08301516157ea60c084018261533d565b5060e083015160e083015261010080840151818401525092915050565b9182526001600160a01b0316602082015260400190565b9384526001600160a01b039283166020850152911660408301521515606082015260800190565b8381526001600160a01b038316602082015261016081016158716040830161586c85614d81565b61533d565b6020830135606083015260408301356080830152606083013560a0830152608083013560c08301526158a560a08401614d81565b6158b260e084018261533d565b506158bf60c08401614d81565b6101006158ce8185018361533d565b60e0850135610120850152808501356101408501525050949350505050565b60006102008201905061590182845161533d565b6020830151615913602084018261533d565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401518184015250610140808401518184015250610160808401516159878285018261533d565b505061018083810151908301526101a080840151908301526101c080840151908301526101e092830151929091019190915290565b90815260200190565b918252602082015260400190565b978852602088019690965260408701949094526060860192909252608085015260a0840152151560c083015260e08201526101000190565b6000813561080a81615b2b565b60ff1981541660ff8315151681178255505050565b615a3f615a3983615a0b565b82615a18565b615a54615a4e60208401615a0b565b82615afa565b60408201356001820155606082013560028201556080820135600382015560a0820135600482015560c0820135600582015560e08201356006820155610100820135600782015561012082013560088201556101408201356009820155615aca615ac16101608401615a0b565b600a8301615a18565b610180820135600b8201556101a0820135600c8201556101c0820135600d8201556101e0820135600e8201555050565b805461ff00191691151560081b61ff0016919091179055565b6001600160a01b0381168114615b2857600080fd5b50565b8015158114615b2857600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c00536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220aa5af7067e5be7ff85d410db3ddfac26a7604c0f18d781e8dd6cb8ad09ba3e9464736f6c63430007060033000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102955760003560e01c8063843d439911610167578063cb67e3b1116100ce578063de2ea94811610087578063de2ea948146105cf578063e468baf0146105e2578063e67f59a7146105f5578063f07456ce14610608578063f25552781461061b578063fbfded6d1461062e57610295565b8063cb67e3b11461054d578063d54d5a9f1461056d578063d8f897c31461058e578063da76524c146105a1578063db97495f146105b4578063dc8f5fac146105c757610295565b8063b136ca4911610120578063b136ca49146104d7578063b1cc53ab146104ea578063b2a2353e146104fd578063c3c7b9e914610512578063c65bc7b114610525578063c72c4d101461053857610295565b8063843d43991461047057806389dea1dc146104835780638a78daa81461049657806393316212146104a957806395082d25146104bc578063a93acac2146104c457610295565b806342e851821161020b5780635bae4263116101c45780635bae4263146103fb5780635c07eaab1461040e5780635da69ed71461042f5780635f7bc119146104425780636be6026b1461045557806382a084901461045d57610295565b806342e851821461036257806348d91abf146103755780634a3f088d14610388578063514ea4bf146103af578063523fba7f146103d557806352f55eed146103e857610295565b80631ce9cb8f1161025d5780631ce9cb8f146102f057806320355a2c1461030357806328a32d5c1461031657806329ff9615146103295780632c668ec11461033c578063421528731461034f57610295565b806303563e671461029a5780630754d4fb146102b85780630842b076146102cd5780630a48d5a9146102d5578063126082cf146102e8575b600080fd5b6102a2610641565b6040516102af91906159bc565b60405180910390f35b6102cb6102c636600461513c565b610646565b005b6102a26106a1565b6102a26102e336600461513c565b6106a7565b6102a2610810565b6102a26102fe366004614d8c565b610816565b6102a2610311366004614d8c565b610828565b6102cb6103243660046150fb565b610b98565b6102a2610337366004614d8c565b610c10565b6102a261034a36600461513c565b610c27565b6102a261035d3660046152f4565b610dfd565b6102a2610370366004614d8c565b610f3f565b6102cb610383366004614fe0565b610f51565b61039b610396366004614e46565b6113ea565b6040516102af9897969594939291906159d3565b6103c26103bd3660046152ac565b6114d4565b6040516102af979695949392919061553e565b6102a26103e3366004614d8c565b611511565b6102a26103f6366004614d8c565b611523565b6102a2610409366004614dc4565b611535565b61042161041c366004615167565b6118c5565b6040516102af929190615476565b6102a261043d366004614dc4565b611986565b6102cb610450366004614d8c565b611dc6565b6102a2611e9e565b6102a261046b366004615039565b611ea5565b6102a261047e36600461521c565b611f1a565b6102cb6104913660046152c4565b611fd8565b6102a26104a4366004614d8c565b611fed565b6102a26104b7366004614dfc565b611fff565b6102a26124f7565b6102a26104d2366004614d8c565b612507565b6102a26104e5366004614d8c565b6125b1565b6102a26104f83660046150bc565b612656565b6105056126ee565b6040516102af91906158ed565b6102a2610520366004614d8c565b61279e565b6102a2610533366004614d8c565b6127b0565b6105406127c2565b6040516102af9190615381565b61056061055b366004614d8c565b6127e6565b6040516102af9190615795565b61058061057b366004614f11565b61287f565b6040516102af9291906159c5565b6102a261059c366004614d8c565b612932565b6102a26105af366004614f73565b612944565b6102a26105c23660046151b8565b6129e5565b6102a2612a76565b6102cb6105dd366004614ea1565b612a7c565b6105406105f03660046152ac565b612f5b565b6102cb610603366004614d8c565b612f88565b6102a2610616366004614d8c565b612ffd565b6102a2610629366004614dc4565b61300f565b6102cb61063c366004614dc4565b613065565b601281565b61064e613243565b6001600160a01b03821660009081526014602052604090205480821115610688576106828361067d84846132f4565b613351565b5061069d565b61069b8361069683856132f4565b613407565b505b5050565b60115490565b6000816106b65750600061080a565b61080760106002016000856001600160a01b03166001600160a01b0316815260200190815260200160002060010154600a0a6108017f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561074457600080fd5b505afa158015610758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077c9190614da8565b6001600160a01b03166376d697608760006040518363ffffffff1660e01b81526004016107aa92919061543a565b60206040518083038186803b1580156107c257600080fd5b505afa1580156107d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fa91906152dc565b85906134da565b90613533565b90505b92915050565b61271081565b601b6020526000908152604090205481565b600060026000541415610870576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005561087d61359a565b6001600160a01b0382166000908152601260205260409020546108a49060ff16600e613645565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190614da8565b905060006109448461367e565b905061095460008211600f613645565b61095e8485613065565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156109b957600080fd5b505afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f19190614da8565b6001600160a01b03166376d697608660006040518363ffffffff1660e01b8152600401610a1f92919061543a565b60206040518083038186803b158015610a3757600080fd5b505afa158015610a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6f91906152dc565b90506000610a8d68327cb2734119d3b7a9601e1b61080185856134da565b9050610a9a818786610dfd565b9050610aaa600082116012613645565b6000610ac668327cb2734119d3b7a9601e1b61080186866134da565b9050610ad3818887610dfd565b9050610adf8782613351565b610ae98785613736565b6040516340c10f1960e01b81526001600160a01b038616906340c10f1990610b1790339085906004016153c6565b600060405180830381600087803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b505050507fc6c8b444f53d4e65122f6f9780fd7db1ff1a47d82ff0cbb2f450eee0c289e534338886846000604051610b81959493929190615395565b60405180910390a160016000559695505050505050565b610ba0613243565b6040516326286a1760e21b81527308858b5ca8ffc1a28c5645a8839f48641801660d906398a1a85c90610bdc9060109086908690600401615845565b60006040518083038186803b158015610bf457600080fd5b505af4158015610c08573d6000803e3d6000fd5b505050505050565b6000610c1f826102e3846125b1565b90505b919050565b6000807f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015610c8357600080fd5b505afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb9190614da8565b6001600160a01b03166376d697608560016040518363ffffffff1660e01b8152600401610ce992919061543a565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3991906152dc565b90506000610d57826108018668327cb2734119d3b7a9601e1b6134da565b9050610df4817f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610db657600080fd5b505afa158015610dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dee9190614da8565b87610dfd565b95945050505050565b6000807f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5957600080fd5b505afa158015610e6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e919190614da8565b90506000816001600160a01b0316856001600160a01b031614610ecf576001600160a01b038516600090815260126020526040902060010154610ed2565b60125b90506000826001600160a01b0316856001600160a01b031614610f10576001600160a01b038516600090815260126020526040902060010154610f13565b60125b9050610f3282600a0a61080183600a0a8a6134da90919063ffffffff16565b93505050505b9392505050565b60146020526000908152604090205481565b60026000541415610f97576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600055610fa4613841565b604051634755223960e01b81527308858b5ca8ffc1a28c5645a8839f48641801660d90634755223990610fe29060109088908890879060040161581e565b60006040518083038186803b158015610ffa57600080fd5b505af415801561100e573d6000803e3d6000fd5b5050600154604080518082019091526002815261064760f31b60208201529250610100900460ff16905061105e5760405162461bcd60e51b81526004016110559190615742565b60405180910390fd5b506110698484613065565b6000611077868686856138f0565b6000818152601a602090815260408083208151631f94a27560e31b81529151949550936001600160a01b037f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c169263fca513a89260048082019391829003018186803b1580156110e657600080fd5b505afa1580156110fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111e9190614da8565b6001600160a01b03166376d6976087866040518363ffffffff1660e01b815260040161114b92919061543a565b60206040518083038186803b15801561116357600080fd5b505afa158015611177573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119b91906152dc565b82549091506111ac57600282018190555b8154158015906111bc5750600085115b156111e2576111dc868360000154846002015487858a88600601546129e5565b60028301555b6000806111fc8a8a8a898b89600001548a60030154613929565b91509150600061120b8a61367e565b905060006112198b836106a7565b600187015490915061122b9082613a94565b6001870181905561124090851115601d613645565b600186015461124f90856132f4565b600187015561125f8b8b8a612656565b60038701558554611270908a613a94565b808755426006880155611286901515601e613645565b61129886600001548760010154613aee565b6112a68c8c8c8b600161287f565b505060006112b68c8b6001613b12565b60048801549091506112c89082613a94565b60048801556112d78c82613c5d565b881561131e576112f08c6112eb8c88613a94565b613cf2565b6112fa8c83613d63565b6113048c84613736565b6113198c6113148e886000613b12565b613dd4565b611328565b6113288b8b613e5b565b7f2fe68525253654c21998f35787a8d0f361905ef647c854092430ab65f2f15022888e8e8e868f8f8d8d604051611367999897969594939291906154da565b60405180910390a17f20853733b590dce729d9f4628682ebd9a34d2354e72679e66f43a008fc03b77388886000015489600101548a600201548b600301548c600401548d600501548d6040516113c498979695949392919061556e565b60405180910390a16113d68c85613ed3565b505060016000555050505050505050505050565b6000806000806000806000806000601a60006114088f8f8f8f6138f0565b81526020019081526020016000206040518060e001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090506000808260a0015113611483578160a00151600003611489565b8160a001515b9050816000015182602001518360400151846060015185608001518560008860a0015112158860c0015199509950995099509950995099509950505094995094995094999196509450565b601a602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b60136020526000908152604090205481565b60156020526000908152604090205481565b60006002600054141561157d576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005561158a61359a565b6001600160a01b0383166000908152601260205260409020546115b19060ff16600e613645565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561160c57600080fd5b505afa158015611620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116449190614da8565b905060006116518261367e565b9050611661600082116012613645565b61166b8586613065565b60006116778683610c27565b9050611687600082116015613645565b6116918683613407565b61169b8682613dd4565b604051632770a7eb60e21b81526001600160a01b03841690639dc29fac906116c990309086906004016153c6565b600060405180830381600087803b1580156116e357600080fd5b505af11580156116f7573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b03861692506370a082319150611727903090600401615381565b60206040518083038186803b15801561173f57600080fd5b505afa158015611753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177791906152dc565b6001600160a01b03841660009081526013602052604080822092909255905163562b7e0760e11b815273686285827f67f13b68baa45c8aa920997f877a0a9063ac56fc0e906117ee907f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c908b908890600401615642565b60206040518083038186803b15801561180657600080fd5b505af415801561181a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183e91906152dc565b905060008061184e898585613fa0565b91509150611860600083116016613645565b61186b89838a61405b565b7ff0769e076d0b71b7205e1d6800e3ede98265f5a21bacbd6067947cbe7a3fa671888a8785876040516118a2959493929190615395565b60405180910390a16118b48982613ed3565b506001600055979650505050505050565b60008073686285827f67f13b68baa45c8aa920997f877a0a63cfb90b207f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c89898989896040518763ffffffff1660e01b815260040161192996959493929190615666565b604080518083038186803b15801561194057600080fd5b505af4158015611954573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611978919061527f565b915091509550959350505050565b6000600260005414156119ce576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b60026000556119db61359a565b6001600160a01b038316600090815260126020526040902054611a029060ff16600e613645565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a5d57600080fd5b505afa158015611a71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a959190614da8565b90506000611aa28561367e565b9050611ab260008211600f613645565b611abc8586613065565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1757600080fd5b505afa158015611b2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4f9190614da8565b6001600160a01b03166376d697608760006040518363ffffffff1660e01b8152600401611b7d92919061543a565b60206040518083038186803b158015611b9557600080fd5b505afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd91906152dc565b90506000611beb68327cb2734119d3b7a9601e1b61080185856134da565b9050611bf8818886610dfd565b9050611c08600082116012613645565b6040516360d41f1560e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063c1a83e2a90611c66907f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c908c908790600401615642565b60206040518083038186803b158015611c7e57600080fd5b505af4158015611c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb691906152dc565b9050600080611cc68a8785613fa0565b90925090506000611ce768327cb2734119d3b7a9601e1b61080185896134da565b9050611cf4818c8a610dfd565b9050611d008b82613351565b611d0a8b84613736565b6040516340c10f1960e01b81526001600160a01b038916906340c10f1990611d38908d9085906004016153c6565b600060405180830381600087803b158015611d5257600080fd5b505af1158015611d66573d6000803e3d6000fd5b505050507fc6c8b444f53d4e65122f6f9780fd7db1ff1a47d82ff0cbb2f450eee0c289e5348a8c898488604051611da1959493929190615395565b60405180910390a1611db38b83613ed3565b60016000559a9950505050505050505050565b60026000541415611e0c576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260009081556001600160a01b038216815260126020526040902054611e379060ff16600e613645565b6000611e428261367e565b9050611e5260008211600f613645565b611e5c8282613736565b7fa5a389190ebf6170a133bda5c769b77f4d6715b8aa172ec0ddf8473d0b4944bd8282604051611e8d9291906153c6565b60405180910390a150506001600055565b620f424081565b600060026000541415611eed576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600055611efa613841565b611f098888888888888861410c565b600160005598975050505050505050565b6040516308e83b0160e21b815260009073686285827f67f13b68baa45c8aa920997f877a0a906323a0ec0490611f7e907f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c908a908a908a908a908a9060040161569e565b60206040518083038186803b158015611f9657600080fd5b505af4158015611faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fce91906152dc565b9695505050505050565b611fe0613243565b80600161069b8282615a2d565b601c6020526000908152604090205481565b600060026000541415612047576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b600260005560015461205d9060ff166017613645565b6001600160a01b0384166000908152601260205260409020546120849060ff16600e613645565b6001600160a01b0383166000908152601260205260409020546120ab9060ff16600e613645565b6120cb836001600160a01b0316856001600160a01b03161415601a613645565b6120d58485613065565b6120df8384613065565b60006120ea8561367e565b90506120fa60008211601b613645565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561215557600080fd5b505afa158015612169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218d9190614da8565b90506000816001600160a01b03166376d697608860006040518363ffffffff1660e01b81526004016121c092919061543a565b60206040518083038186803b1580156121d857600080fd5b505afa1580156121ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221091906152dc565b90506000826001600160a01b03166376d697608860016040518363ffffffff1660e01b815260040161224392919061543a565b60206040518083038186803b15801561225b57600080fd5b505afa15801561226f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229391906152dc565b905060006122a58261080187866134da565b90506122b2818a8a610dfd565b905060006122d068327cb2734119d3b7a9601e1b61080188876134da565b9050612368818b7f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316638ad6de4e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561233057600080fd5b505afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d9190614da8565b9050600073686285827f67f13b68baa45c8aa920997f877a0a6387e35c2c7f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c8d8d866040518563ffffffff1660e01b81526004016123c99493929190615618565b60206040518083038186803b1580156123e157600080fd5b505af41580156123f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241991906152dc565b90506000806124298c8685613fa0565b915091506124378d85613351565b6124418c85613407565b61244b8d8a613736565b6124558c86613dd4565b6001600160a01b038c1660009081526012602090815260408083206006015460159092529091205461248a9111156064613645565b6124958c838d61405b565b7f0874b2d545cb271cdbda4e093020c452328b24af12382ed62c4d00f5c26709db8b8e8e8c8987896040516124d097969594939291906153f9565b60405180910390a16124e28c82613ed3565b5060016000559b9a5050505050505050505050565b68327cb2734119d3b7a9601e1b81565b6040516246b9f360e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a90628d73e690612561907f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c9086906004016153df565b60206040518083038186803b15801561257957600080fd5b505af415801561258d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1f91906152dc565b6001600160a01b03811660009081526012602052604081206005015460ff16156125f457506001600160a01b038116600090815260156020526040902054610c22565b6001600160a01b03821660009081526017602052604081205461261990849083613b12565b6001600160a01b038416600090815260166020908152604080832054601590925290912054919250610f3891612650908490613a94565b906132f4565b60405163429a429f60e01b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063429a429f90612696903090889088908890600401615718565b60206040518083038186803b1580156126ae57600080fd5b505af41580156126c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e691906152dc565b949350505050565b6126f6614cac565b50604080516102008101825260015460ff8082161515835261010091829004811615156020840152600254938301939093526003546060830152600454608083015260055460a083015260065460c083015260075460e083015260085490820152600954610120820152600a54610140820152600b549091161515610160820152600c54610180820152600d546101a0820152600e546101c0820152600f546101e082015290565b60166020526000908152604090205481565b60186020526000908152604090205481565b7f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c81565b6127ee614d2f565b506001600160a01b0316600090815260126020908152604091829020825161012081018452815460ff9081161515825260018301549382019390935260028201549381019390935260038101546060840152600481015460808401526005810154808316151560a085015261010090819004909216151560c0840152600681015460e0840152600701549082015290565b60008073686285827f67f13b68baa45c8aa920997f877a0a634e9c91757f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c89898989896040518763ffffffff1660e01b81526004016128e3969594939291906155a4565b604080518083038186803b1580156128fa57600080fd5b505af415801561290e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611978919061531a565b60196020526000908152604090205481565b604051636df5632b60e11b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063dbeac6569061298a9030908b908b908b908b908b908b906004016156d4565b60206040518083038186803b1580156129a257600080fd5b505af41580156129b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129da91906152dc565b979650505050505050565b60008060006129f78a8a8a8a886118c5565b90925090506000612a088a87613a94565b905060008815612a375783612a2657612a2182846132f4565b612a30565b612a308284613a94565b9050612a58565b83612a4b57612a468284613a94565b612a55565b612a5582846132f4565b90505b612a66816108018a856134da565b9c9b505050505050505050505050565b60105490565b60026000541415612ac2576040805162461bcd60e51b815260206004820152601f6024820152600080516020615b3a833981519152604482015290519081900360640190fd5b6002600081905550612b79336001600160a01b03167f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b0316636a22dede6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b3057600080fd5b505afa158015612b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b689190614da8565b6001600160a01b0316146022613645565b612b838484613065565b6000612b91868686866138f0565b6000818152601a6020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015291925090612c00901515601f613645565b600080612c1189898989600061287f565b91509150612c2482600014156024613645565b8160021415612c4b57612c41898989600087600001518b8f61410c565b5050505050612f4f565b6000612c5989836000613b12565b6001600160a01b038a166000908152601b6020526040902054909150612c7f9082613a94565b6001600160a01b038a166000908152601b60205260409081902091909155517f5d0c0019d3d45fadeb74eff9d2c9924d146d000ac6bcf3c28bf0ac3c9baa011a90612ccf908b9085908590615455565b60405180910390a1612ce589856080015161466f565b8615612d165760208401518451612d06918b91612d01916132f4565b613d63565b612d16896113148b856000613b12565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7157600080fd5b505afa158015612d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da99190614da8565b6001600160a01b03166376d697608a8a156040518363ffffffff1660e01b8152600401612dd792919061543a565b60206040518083038186803b158015612def57600080fd5b505afa158015612e03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e2791906152dc565b90507f2e1f85a64a2f22cf2f0c42584e7c919ed4abe8d53675cff0f62bf1e95a1c676f868c8c8c8c8a600001518b602001518c608001518d60a001518a604051612e7a9a99989796959493929190615486565b60405180910390a187158015612e935750846020015183105b15612ec3576020850151600090612eaa90856132f4565b9050612ec18b612ebc8d846000613b12565b613736565b505b87612ed657612ed6898660000151614718565b6000868152601a60205260408120818155600181018290556002810182905560038101829055600481018290556005810182905560060181905560095490612f27908c906113149082908590613b12565b612f3d8b612f378d846000613b12565b8a61405b565b612f478b84613ed3565b505050505050505b50506001600055505050565b600060106001018281548110612f6d57fe5b6000918252602090912001546001600160a01b031692915050565b612f90613243565b604051632e43d10160e01b81527308858b5ca8ffc1a28c5645a8839f48641801660d90632e43d10190612fca906010908590600401615807565b60006040518083038186803b158015612fe257600080fd5b505af4158015612ff6573d6000803e3d6000fd5b5050505050565b60176020526000908152604090205481565b600061301961359a565b6001600160a01b0383166000908152601b60205260409020548061304157600091505061080a565b6001600160a01b0384166000908152601b602052604081205561080784828561405b565b60405163fbfded6d60e01b815260009073686285827f67f13b68baa45c8aa920997f877a0a9063fbfded6d906130a190869086906004016153df565b60206040518083038186803b1580156130b957600080fd5b505af41580156130cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f19190615263565b9050806130fe575061069d565b600d546001600160a01b038416600090815260196020526040902054613153576131328161312c4282613533565b906134da565b6001600160a01b0385166000908152601960205260409020555061069d9050565b6001600160a01b03841660009081526019602052604090205442906131789083613a94565b111561318557505061069d565b600061319085612507565b6001600160a01b0386166000908152601860205260409020549091506131b69082613a94565b6001600160a01b0386166000908152601860205260409020556131dd8261312c4282613533565b6001600160a01b038616600090815260196020908152604080832093909355601890528190205490517fa146fc154e1913322e9817d49f0d5c37466c24326e15de10e739a948be815eab91613234918891906153c6565b60405180910390a15050505050565b6132f27f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663d759932b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561329f57600080fd5b505afa1580156132b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d79190614da8565b6001600160a01b0316336001600160a01b0316146066613645565b565b60008282111561334b576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b0382166000908152601460205260409020546133749082613a94565b6001600160a01b03831660009081526014602090815260408083209390935560129052206004015480156133c9576001600160a01b0383166000908152601460205260409020546133c9908210156033613645565b7ffbf914421322be849bbd116e701fe46b8e6b903e15192c1d479b8748a738452083836040516133fa9291906153c6565b60405180910390a1505050565b6001600160a01b038216600090815260146020526040902054818111613482576001600160a01b03831660009081526014602052604080822091909155517fda43d5cdf64be33afb6f3e9858581d78f3855a1f6fcb50e5eb86c0c5db312d1c9061347490859084906153c6565b60405180910390a15061069d565b61348c81836132f4565b6001600160a01b0384166000908152601460205260409081902091909155517fda43d5cdf64be33afb6f3e9858581d78f3855a1f6fcb50e5eb86c0c5db312d1c906133fa90859085906153c6565b6000826134e95750600061080a565b828202828482816134f657fe5b04146108075760405162461bcd60e51b8152600401808060200182810382526021815260200180615b5a6021913960400191505060405180910390fd5b6000808211613589576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161359257fe5b049392505050565b6132f27f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663028d27d86040518163ffffffff1660e01b815260040160206040518083038186803b1580156135f657600080fd5b505afa15801561360a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362e9190614da8565b6001600160a01b0316336001600160a01b03161460365b60405163cda9d28760e01b8152730ef7e7d6944bb4d8c710f2418c75d8881174f4fd9063cda9d28790610bdc9085908590600401615476565b6001600160a01b0381166000818152601360205260408082205490516370a0823160e01b8152919290918391906370a08231906136bf903090600401615381565b60206040518083038186803b1580156136d757600080fd5b505afa1580156136eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061370f91906152dc565b6001600160a01b038516600090815260136020526040902081905590506126e681836132f4565b6001600160a01b0382166000908152601560205260409020546137599082613a94565b6001600160a01b0383166000818152601560205260408082209390935591516370a0823160e01b81526370a0823190613796903090600401615381565b60206040518083038186803b1580156137ae57600080fd5b505afa1580156137c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e691906152dc565b6001600160a01b038416600090815260156020526040902054909150613810908210156031613645565b7f976177fbe09a15e5e43f848844963a42b41ef919ef17ff21a17a5421de8f473783836040516133fa9291906153c6565b6132f27f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b15801561389d57600080fd5b505afa1580156138b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d59190614da8565b6001600160a01b0316336001600160a01b0316146067613645565b6000848484846040516020016139099493929190615343565b604051602081830303815290604052805190602001209050949350505050565b60008060006139f661393f8b8b8b8b8a8a612944565b73686285827f67f13b68baa45c8aa920997f877a0a63d4b9aa637f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c8e8e8e8e8e6040518763ffffffff1660e01b81526004016139a0969594939291906155de565b60206040518083038186803b1580156139b857600080fd5b505af41580156139cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f091906152dc565b90613a94565b90506000613a068a836000613b12565b6001600160a01b038b166000908152601b6020526040902054909150613a2c9082613a94565b6001600160a01b038b166000908152601b60205260409081902091909155517f5d0c0019d3d45fadeb74eff9d2c9924d146d000ac6bcf3c28bf0ac3c9baa011a90613a7c908c9085908590615455565b60405180910390a1909a909950975050505050505050565b600082820183811015610807576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b81613b0457613aff81156027613645565b61069d565b61069d818310156028613645565b600082613b2157506000610f38565b6126e67f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015613b7d57600080fd5b505afa158015613b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb59190614da8565b6001600160a01b03166376d697608685156040518363ffffffff1660e01b8152600401613be392919061543a565b60206040518083038186803b158015613bfb57600080fd5b505afa158015613c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3391906152dc565b6001600160a01b038616600090815260126020526040902060010154610801908690600a0a6134da565b6001600160a01b038216600090815260166020526040902054613c809082613a94565b6001600160a01b038316600090815260166020818152604080842085905560158252909220549152613cb59111156032613645565b7faa5649d82f5462be9d19b0f2b31a59b2259950a6076550bac9f3a1c07db9f66d8282604051613ce69291906153c6565b60405180910390a15050565b6001600160a01b038216600090815260176020526040902054613d159082613a94565b6001600160a01b0383166000908152601760205260409081902091909155517fd9d4761f75e0d0103b5cbeab941eeb443d7a56a35b5baf2a0787c03f03f4e47490613ce690849084906153c6565b6001600160a01b038216600090815260176020526040902054613d8690826132f4565b6001600160a01b0383166000908152601760205260409081902091909155517f34e07158b9db50df5613e591c44ea2ebc82834eff4a4dc3a46e000e608261d6890613ce690849084906153c6565b6001600160a01b038216600090815260156020526040902054613df790826132f4565b6001600160a01b03831660009081526015602090815260408083208490556016909152902054613e2a9110156032613645565b7f112726233fbeaeed0f5b1dba5cb0b2b81883dee49fb35ff99fd98ed9f6d31eb08282604051613ce69291906153c6565b6001600160a01b0382166000908152601c6020526040902054613e7e9082613a94565b6001600160a01b0383166000908152601c6020908152604080832093909355601290522060070154801561069b576001600160a01b0383166000908152601c602052604090205461069b908210156065613645565b6000613ef86127106108016107fa6001600b01546127106132f490919063ffffffff16565b9050801561069b576001600160a01b0383166000908152601b6020526040902054613f2390826132f4565b6001600160a01b0384166000908152601b6020908152604080832093909355601590522054613f529082613a94565b6001600160a01b0384166000908152601560205260409081902091909155517fe1f042ea063a41fdab4bcdfa4b5e9036c3444aead3f6e901aa5073a9f72e8abd906133fa90859084906153c6565b60008080613fbe612710610801613fb782886132f4565b88906134da565b90506000613fcc86836132f4565b6001600160a01b0388166000908152601b6020526040902054909150613ff29082613a94565b6001600160a01b0388166000908152601b60205260409020557f47cd9dda0e50ce30bcaaacd0488452b596221c07ac402a581cfae4d3933cac2b8761403781846106a7565b8360405161404793929190615455565b60405180910390a190969095509350505050565b61406f6001600160a01b0384168284614780565b6040516370a0823160e01b81526001600160a01b038416906370a082319061409b903090600401615381565b60206040518083038186803b1580156140b357600080fd5b505afa1580156140c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140eb91906152dc565b6001600160a01b039093166000908152601360205260409020929092555050565b60006141188787613065565b6000614126898989876138f0565b6000818152601a60205260409020805491925090614147901515601f613645565b61415986826000015410156020613645565b61416b87826001015410156021613645565b60018101548154600483015460009161418891610801908b6134da565b600484015490915061419a90826132f4565b60048401556141a98b8261466f565b506000806141bb8d8d8d8d8d8d6147d2565b8554919350915089146143f7576141d38c8c8a612656565b600385015583546141e4908a6132f4565b80855560018501546141f69190613aee565b6142048d8d8d8b600161287f565b50508715614231576142278c6112eb8660010154866132f490919063ffffffff16565b6142318c8a613d63565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561428c57600080fd5b505afa1580156142a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142c49190614da8565b6001600160a01b03166376d697608d8b156040518363ffffffff1660e01b81526004016142f292919061543a565b60206040518083038186803b15801561430a57600080fd5b505afa15801561431e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061434291906152dc565b90507f93d75d64d1f84fc6f430a64fc578bdd4c1e090e90ea2d51773e626d19de56d30868f8f8f8f8f8f886143778c8c6132f4565b60405161438c999897969594939291906154da565b60405180910390a17f20853733b590dce729d9f4628682ebd9a34d2354e72679e66f43a008fc03b7738686600001548760010154886002015489600301548a600401548b60050154886040516143e998979695949392919061556e565b60405180910390a150614609565b8715614411576144078c84613cf2565b6144118c8a613d63565b60007f000000000000000000000000b29ea150c870ea830d9890d94f326cb1b273ce8c6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561446c57600080fd5b505afa158015614480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144a49190614da8565b6001600160a01b03166376d697608d8b156040518363ffffffff1660e01b81526004016144d292919061543a565b60206040518083038186803b1580156144ea57600080fd5b505afa1580156144fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061452291906152dc565b90507f93d75d64d1f84fc6f430a64fc578bdd4c1e090e90ea2d51773e626d19de56d30868f8f8f8f8f8f886145578c8c6132f4565b60405161456c999897969594939291906154da565b60405180910390a17f73af1d417d82c240fdb6d319b34ad884487c6bf2845d98980cc52ad9171cb4558686600001548760010154886002015489600301548a600401548b600501546040516145c7979695949392919061553e565b60405180910390a1506000858152601a602052604081208181556001810182905560028101829055600381018290556004810182905560058101829055600601555b87614618576146188b8a614718565b811561465c578715614634576146348c6113148e856000613b12565b60006146428d836000613b12565b905061464f8d828a61405b565b95506129da945050505050565b5060009c9b505050505050505050505050565b604080518082018252601b81527f5661756c743a20696e73756666696369656e74207265736572766500000000006020808301919091526001600160a01b0385166000908152601690915291909120546146ca9183906149de565b6001600160a01b0383166000908152601660205260409081902091909155517f533cb5ed32be6a90284e96b5747a1bfc2d38fdb5768a6b5f67ff7d62144ed67b90613ce690849084906153c6565b6001600160a01b0382166000908152601c60205260409020548082111561475857506001600160a01b0382166000908152601c602052604081205561069d565b61476281836132f4565b6001600160a01b0384166000908152601c6020526040902055505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261069b908490614a75565b6000806000806000806147e78c8c8c8a6138f0565b9050601a6000828152602001908152602001600020935060008061481a8c876000015488600201548c8a600601546118c5565b87549196508693509150614832906108018c846134da565b93507f3ff41bdde87755b687ae83d0221a232b6be51a803330ed9661c1b5d0105e0d8a83868660405161486793929190615528565b60405180910390a150505060008061488c8d8d8d8b8d8a600001548b60030154613929565b91509150600084801561489f5750600084115b156148d157506005850180548401905582886148d15760006148c38e866000613b12565b90506148cf8e82613dd4565b505b841580156148df5750600084115b156149255760018601546148f390856132f4565b60018701558861491957600061490b8e866000613b12565b90506149178e82613736565b505b60058601805485900390555b8a1561494d57614935818c613a94565b6001870154909150614947908c6132f4565b60018701555b85548a1415614970576001860154614966908290613a94565b6000600188015590505b808381111561498a5761498382856132f4565b90506149c0565b600187015461499990856132f4565b600188015589156149c05760006149b28f866000613b12565b90506149be8f82613dd4565b505b6149ca8e84613ed3565b909e909d509b505050505050505050505050565b60008184841115614a6d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614a32578181015183820152602001614a1a565b50505050905090810190601f168015614a5f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000614aca826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b269092919063ffffffff16565b80519091501561069b57808060200190516020811015614ae957600080fd5b505161069b5760405162461bcd60e51b815260040180806020018281038252602a815260200180615b7b602a913960400191505060405180910390fd5b60606126e6848460008585614b3a85614c40565b614b8b576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310614bc95780518252601f199092019160209182019101614baa565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614c2b576040519150601f19603f3d011682016040523d82523d6000602084013e614c30565b606091505b50915091506129da828286614c46565b3b151590565b60608315614c55575081610f38565b825115614c655782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315614a32578181015183820152602001614a1a565b604051806102000160405280600015158152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081525090565b6040518061012001604052806000151581526020016000815260200160008152602001600081526020016000815260200160001515815260200160001515815260200160008152602001600081525090565b8035610c2281615b2b565b600060208284031215614d9d578081fd5b813561080781615b13565b600060208284031215614db9578081fd5b815161080781615b13565b60008060408385031215614dd6578081fd5b8235614de181615b13565b91506020830135614df181615b13565b809150509250929050565b600080600060608486031215614e10578081fd5b8335614e1b81615b13565b92506020840135614e2b81615b13565b91506040840135614e3b81615b13565b809150509250925092565b60008060008060808587031215614e5b578081fd5b8435614e6681615b13565b93506020850135614e7681615b13565b92506040850135614e8681615b13565b91506060850135614e9681615b2b565b939692955090935050565b600080600080600060a08688031215614eb8578081fd5b8535614ec381615b13565b94506020860135614ed381615b13565b93506040860135614ee381615b13565b92506060860135614ef381615b2b565b91506080860135614f0381615b13565b809150509295509295909350565b600080600080600060a08688031215614f28578081fd5b8535614f3381615b13565b94506020860135614f4381615b13565b93506040860135614f5381615b13565b92506060860135614f6381615b2b565b91506080860135614f0381615b2b565b60008060008060008060c08789031215614f8b578081fd5b8635614f9681615b13565b95506020870135614fa681615b13565b94506040870135614fb681615b13565b93506060870135614fc681615b2b565b9598949750929560808101359460a0909101359350915050565b600080600080600060a08688031215614ff7578081fd5b853561500281615b13565b9450602086013561501281615b13565b9350604086013561502281615b13565b9250606086013591506080860135614f0381615b2b565b600080600080600080600060e0888a031215615053578485fd5b873561505e81615b13565b9650602088013561506e81615b13565b9550604088013561507e81615b13565b9450606088013593506080880135925060a088013561509c81615b2b565b915060c08801356150ac81615b13565b8091505092959891949750929550565b6000806000606084860312156150d0578081fd5b83356150db81615b13565b925060208401356150eb81615b13565b91506040840135614e3b81615b2b565b60008082840361014081121561510f578283fd5b833561511a81615b13565b9250610120601f198201121561512e578182fd5b506020830190509250929050565b6000806040838503121561514e578182fd5b823561515981615b13565b946020939093013593505050565b600080600080600060a0868803121561517e578283fd5b853561518981615b13565b9450602086013593506040860135925060608601356151a781615b2b565b949793965091946080013592915050565b600080600080600080600060e0888a0312156151d2578081fd5b87356151dd81615b13565b9650602088013595506040880135945060608801356151fb81615b2b565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600060a08688031215615233578283fd5b853561523e81615b13565b94506020860135935060408601359250606086013591506080860135614f0381615b2b565b600060208284031215615274578081fd5b815161080781615b2b565b60008060408385031215615291578182fd5b825161529c81615b2b565b6020939093015192949293505050565b6000602082840312156152bd578081fd5b5035919050565b600061020082840312156152d6578081fd5b50919050565b6000602082840312156152ed578081fd5b5051919050565b600080600060608486031215615308578081fd5b833592506020840135614e2b81615b13565b6000806040838503121561532c578182fd5b505080516020909101519092909150565b15159052565b6bffffffffffffffffffffffff19606095861b8116825293851b841660148201529190931b909116602882015290151560f81b603c820152603d0190565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03978816815295871660208701529390951660408501526060840191909152608083015260a082019290925260c081019190915260e00190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b9115158252602082015260400190565b998a526001600160a01b0398891660208b015296881660408a0152949096166060880152911515608087015260a086015260c085015260e08401929092526101008301919091526101208201526101400190565b9889526001600160a01b0397881660208a01529587166040890152939095166060870152608086019190915260a085015291151560c084015260e08301919091526101008201526101200190565b9283529015156020830152604082015260600190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152911515608082015290151560a082015260c00190565b6001600160a01b0396871681529486166020860152928516604085015293166060830152911515608082015260a081019190915260c00190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039687168152949095166020850152604084019290925260608301521515608082015260a081019190915260c00190565b6001600160a01b03968716815294909516602085015260408401929092526060830152608082015290151560a082015260c00190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152921515608083015260a082019290925260c081019190915260e00190565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000602080835283518082850152825b8181101561576e57858101830151858201604001528201615752565b8181111561577f5783604083870101525b50601f01601f1916929092016040019392505050565b6000610120820190508251151582526020830151602083015260408301516040830152606083015160608301526080830151608083015260a0830151151560a083015260c08301516157ea60c084018261533d565b5060e083015160e083015261010080840151818401525092915050565b9182526001600160a01b0316602082015260400190565b9384526001600160a01b039283166020850152911660408301521515606082015260800190565b8381526001600160a01b038316602082015261016081016158716040830161586c85614d81565b61533d565b6020830135606083015260408301356080830152606083013560a0830152608083013560c08301526158a560a08401614d81565b6158b260e084018261533d565b506158bf60c08401614d81565b6101006158ce8185018361533d565b60e0850135610120850152808501356101408501525050949350505050565b60006102008201905061590182845161533d565b6020830151615913602084018261533d565b5060408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401518184015250610140808401518184015250610160808401516159878285018261533d565b505061018083810151908301526101a080840151908301526101c080840151908301526101e092830151929091019190915290565b90815260200190565b918252602082015260400190565b978852602088019690965260408701949094526060860192909252608085015260a0840152151560c083015260e08201526101000190565b6000813561080a81615b2b565b60ff1981541660ff8315151681178255505050565b615a3f615a3983615a0b565b82615a18565b615a54615a4e60208401615a0b565b82615afa565b60408201356001820155606082013560028201556080820135600382015560a0820135600482015560c0820135600582015560e08201356006820155610100820135600782015561012082013560088201556101408201356009820155615aca615ac16101608401615a0b565b600a8301615a18565b610180820135600b8201556101a0820135600c8201556101c0820135600d8201556101e0820135600e8201555050565b805461ff00191691151560081b61ff0016919091179055565b6001600160a01b0381168114615b2857600080fd5b50565b8015158114615b2857600080fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c00536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220aa5af7067e5be7ff85d410db3ddfac26a7604c0f18d781e8dd6cb8ad09ba3e9464736f6c63430007060033

External libraries