false
true
0

Contract Address Details

0x6e5A59C31cB98B7E403295DfC2A3352De6b6Be87

Contract Name
PositionRouter
Creator
0x64e7ff–1c04a3 at 0x5ed48d–9c66e4
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
62,419 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
25960574
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
PositionRouter




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




Optimization runs
200
EVM Version
istanbul




Verified at
2024-06-07T06:59:41.498762Z

Constructor Arguments

0x0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000a2a15d09519be00000

Arg [0] (address) : 0x3cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1
Arg [1] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27
Arg [2] (uint256) : 30
Arg [3] (uint256) : 3000000000000000000000

              

contracts/protocol/core/PositionRouter.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

import "../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../dependencies/openzeppelin/contracts/SafeERC20.sol";
import "../../interfaces/IRouter.sol";
import "../../interfaces/IPositionRouter.sol";
import "./BasePositionManager.sol";

contract PositionRouter is BasePositionManager, IPositionRouter {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    struct IncreasePositionRequest {
        address account;
        address[] path;
        address indexToken;
        uint256 amountIn;
        uint256 minOut;
        uint256 sizeDelta;
        bool isLong;
        uint256 acceptablePrice;
        uint256 executionFee;
        uint256 blockNumber;
        uint256 blockTime;
        bool hasCollateralInETH;
    }

    struct DecreasePositionRequest {
        address account;
        address[] path;
        address indexToken;
        uint256 collateralDelta;
        uint256 sizeDelta;
        bool isLong;
        address receiver;
        uint256 acceptablePrice;
        uint256 minOut;
        uint256 executionFee;
        uint256 blockNumber;
        uint256 blockTime;
        bool withdrawETH;
    }

    uint256 public constant MAX_MIN_EXECUTION_FEE = 1e24;
    uint256 public constant MAX_MIN_BLOCK_DELAY_KEEPER = 10;
    uint256 public constant MAX_MAX_TIME_DELAY = 3600;

    uint256 public minExecutionFee;

    uint256 public minBlockDelayKeeper;
    uint256 public maxTimeDelay;

    bytes32[] public override increasePositionRequestKeys;
    bytes32[] public override decreasePositionRequestKeys;

    uint256 public override increasePositionRequestKeysStart;
    uint256 public override decreasePositionRequestKeysStart;

    mapping(address => bool) public isPositionKeeper;

    mapping(address => uint256) public increasePositionsIndex;
    mapping(bytes32 => IncreasePositionRequest) public increasePositionRequests;

    mapping(address => uint256) public decreasePositionsIndex;
    mapping(bytes32 => DecreasePositionRequest) public decreasePositionRequests;

    modifier onlyPositionKeeper() {
        require(
            isPositionKeeper[msg.sender],
            "PositionRouter: caller is not the position keeper"
        );
        _;
    }

    constructor(
        IAddressesProvider addressesProvider_,
        address _weth,
        uint256 _depositFee,
        uint256 _minExecutionFee
    ) BasePositionManager(addressesProvider_, _weth, _depositFee) {
        require(
            _minExecutionFee <= MAX_MIN_EXECUTION_FEE,
            "PositionRouter: minExecutionFee is too high"
        );
        minExecutionFee = _minExecutionFee;
        isPositionKeeper[address(this)] = true;
    }

    function setPositionKeeper(
        address _account,
        bool _isActive
    ) external onlyOwner {
        isPositionKeeper[_account] = _isActive;
        emit SetPositionKeeper(_account, _isActive);
    }

    function setMinExecutionFee(uint256 _minExecutionFee) external onlyOwner {
        require(
            _minExecutionFee <= MAX_MIN_EXECUTION_FEE,
            "PositionRouter: minExecutionFee is too high"
        );
        minExecutionFee = _minExecutionFee;
        emit SetMinExecutionFee(_minExecutionFee);
    }

    function setDelayValues(
        uint256 _minBlockDelayKeeper,
        uint256 _maxTimeDelay
    ) external onlyOwner {
        require(
            _minBlockDelayKeeper <= MAX_MIN_BLOCK_DELAY_KEEPER,
            "PositionRouter: minBlockDelayKeeper is too high"
        );
        require(
            _maxTimeDelay <= MAX_MAX_TIME_DELAY,
            "PositionRouter: maxTimeDelay is too high"
        );
        minBlockDelayKeeper = _minBlockDelayKeeper;
        maxTimeDelay = _maxTimeDelay;
        emit SetDelayValues(_minBlockDelayKeeper, _maxTimeDelay);
    }

    function setRequestKeysStartValues(
        uint256 _increasePositionRequestKeysStart,
        uint256 _decreasePositionRequestKeysStart
    ) external onlyOwner {
        require(
            _increasePositionRequestKeysStart <=
                increasePositionRequestKeys.length,
            "PositionRouter: increasePositionRequestKeysStart is too high"
        );
        require(
            _decreasePositionRequestKeysStart <=
                decreasePositionRequestKeys.length,
            "PositionRouter: decreasePositionRequestKeysStart is too high"
        );

        increasePositionRequestKeysStart = _increasePositionRequestKeysStart;
        decreasePositionRequestKeysStart = _decreasePositionRequestKeysStart;

        emit SetRequestKeysStartValues(
            _increasePositionRequestKeysStart,
            _decreasePositionRequestKeysStart
        );
    }

    function executeIncreasePositions(
        uint256 _endIndex,
        address payable _executionFeeReceiver
    ) external override onlyPositionKeeper {
        uint256 index = increasePositionRequestKeysStart;
        uint256 length = increasePositionRequestKeys.length;

        if (index >= length) {
            return;
        }

        if (_endIndex > length) {
            _endIndex = length;
        }

        while (index < _endIndex) {
            bytes32 key = increasePositionRequestKeys[index];

            // if the request was executed then delete the key from the array
            // if the request was not executed then break from the loop, this can happen if the
            // minimum number of blocks has not yet passed
            // an error could be thrown if the request is too old or if the slippage is
            // higher than what the user specified, or if there is insufficient liquidity for the position
            // in case an error was thrown, cancel the request
            try
                this.executeIncreasePosition(key, _executionFeeReceiver)
            returns (bool _wasExecuted) {
                if (!_wasExecuted) {
                    break;
                }
            } catch {
                // wrap this call in a try catch to prevent invalid cancels from blocking the loop
                try
                    this.cancelIncreasePosition(key, _executionFeeReceiver)
                returns (bool _wasCancelled) {
                    if (!_wasCancelled) {
                        break;
                    }
                } catch {}
            }

            delete increasePositionRequestKeys[index];
            index++;
        }

        increasePositionRequestKeysStart = index;
    }

    function executeDecreasePositions(
        uint256 _endIndex,
        address payable _executionFeeReceiver
    ) external override onlyPositionKeeper {
        uint256 index = decreasePositionRequestKeysStart;
        uint256 length = decreasePositionRequestKeys.length;

        if (index >= length) {
            return;
        }

        if (_endIndex > length) {
            _endIndex = length;
        }

        while (index < _endIndex) {
            bytes32 key = decreasePositionRequestKeys[index];

            // if the request was executed then delete the key from the array
            // if the request was not executed then break from the loop, this can happen if the
            // minimum number of blocks has not yet passed
            // an error could be thrown if the request is too old
            // in case an error was thrown, cancel the request
            try
                this.executeDecreasePosition(key, _executionFeeReceiver)
            returns (bool _wasExecuted) {
                if (!_wasExecuted) {
                    break;
                }
            } catch {
                // wrap this call in a try catch to prevent invalid cancels from blocking the loop
                try
                    this.cancelDecreasePosition(key, _executionFeeReceiver)
                returns (bool _wasCancelled) {
                    if (!_wasCancelled) {
                        break;
                    }
                } catch {}
            }

            delete decreasePositionRequestKeys[index];
            index++;
        }

        decreasePositionRequestKeysStart = index;
    }

    function createIncreasePosition(
        address[] memory _path,
        address _indexToken,
        uint256 _amountIn,
        uint256 _minOut,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 _executionFee
    ) external payable nonReentrant {
        require(
            _executionFee >= minExecutionFee,
            "PositionRouter: invalid executionFee"
        );
        require(
            msg.value == _executionFee,
            "PositionRouter: invalid msg.value"
        );
        require(
            _path.length == 1 || _path.length == 2,
            "PositionRouter: invalid _path length"
        );

        _transferInETH();

        if (_amountIn > 0) {
            IRouter(addressesProvider.getRouter()).pluginTransfer(
                _path[0],
                msg.sender,
                address(this),
                _amountIn
            );
        }

        _createIncreasePosition(
            msg.sender,
            _path,
            _indexToken,
            _amountIn,
            _minOut,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            _executionFee,
            false
        );
    }

    function createIncreasePositionETH(
        address[] memory _path,
        address _indexToken,
        uint256 _minOut,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 _executionFee
    ) external payable nonReentrant {
        require(
            _executionFee >= minExecutionFee,
            "PositionRouter: invalid executionFee"
        );
        require(
            msg.value >= _executionFee,
            "PositionRouter: invalid msg.value"
        );
        require(
            _path.length == 1 || _path.length == 2,
            "PositionRouter: invalid _path length"
        );
        require(_path[0] == weth, "PositionRouter: invalid _path");

        _transferInETH();

        uint256 amountIn = msg.value.sub(_executionFee);

        _createIncreasePosition(
            msg.sender,
            _path,
            _indexToken,
            amountIn,
            _minOut,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            _executionFee,
            true
        );
    }

    function createDecreasePosition(
        address[] memory _path,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _acceptablePrice,
        uint256 _minOut,
        uint256 _executionFee,
        bool _withdrawETH
    ) external payable nonReentrant {
        require(
            _executionFee >= minExecutionFee,
            "PositionRouter: invalid executionFee"
        );
        require(
            msg.value == _executionFee,
            "PositionRouter: invalid msg.value"
        );
        require(
            _path.length == 1 || _path.length == 2,
            "PositionRouter: invalid _path length"
        );

        if (_withdrawETH) {
            require(
                _path[_path.length - 1] == weth,
                "PositionRouter: invalid _path"
            );
        }

        _transferInETH();

        _createDecreasePosition(
            msg.sender,
            _path,
            _indexToken,
            _collateralDelta,
            _sizeDelta,
            _isLong,
            _receiver,
            _acceptablePrice,
            _minOut,
            _executionFee,
            _withdrawETH
        );
    }

    function getRequestQueueLengths()
        external
        view
        returns (uint256, uint256, uint256, uint256)
    {
        return (
            increasePositionRequestKeysStart,
            increasePositionRequestKeys.length,
            decreasePositionRequestKeysStart,
            decreasePositionRequestKeys.length
        );
    }

    function executeIncreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        IncreasePositionRequest memory request = increasePositionRequests[_key];
        // if the request was already executed or cancelled, return true so that the executeIncreasePositions loop will continue executing the next request
        if (request.account == address(0)) {
            return true;
        }

        bool shouldExecute = _validateExecution(
            request.blockNumber,
            request.blockTime,
            request.account
        );
        if (!shouldExecute) {
            return false;
        }

        delete increasePositionRequests[_key];

        if (request.amountIn > 0) {
            uint256 amountIn = request.amountIn;

            address vault = addressesProvider.getVault();

            if (request.path.length > 1) {
                IERC20(request.path[0]).safeTransfer(vault, request.amountIn);
                amountIn = _swap(request.path, request.minOut, address(this));
            }

            uint256 afterFeeAmount = _collectFees(
                request.account,
                request.path,
                amountIn,
                request.indexToken,
                request.isLong,
                request.sizeDelta
            );
            IERC20(request.path[request.path.length - 1]).safeTransfer(
                vault,
                afterFeeAmount
            );
        }

        _increasePosition(
            request.account,
            request.path[request.path.length - 1],
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            request.acceptablePrice
        );

        _transferOutETHWithGasLimitFallbackToWeth(
            request.executionFee,
            _executionFeeReceiver
        );

        emit ExecuteIncreasePosition(
            request.account,
            request.path,
            request.indexToken,
            request.amountIn,
            request.minOut,
            request.sizeDelta,
            request.isLong,
            request.acceptablePrice,
            request.executionFee,
            block.number.sub(request.blockNumber),
            block.timestamp.sub(request.blockTime)
        );

        return true;
    }

    function cancelIncreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        IncreasePositionRequest memory request = increasePositionRequests[_key];
        // if the request was already executed or cancelled, return true so that the executeIncreasePositions loop will continue executing the next request
        if (request.account == address(0)) {
            return true;
        }

        bool shouldCancel = _validateCancellation(
            request.blockNumber,
            request.blockTime,
            request.account
        );
        if (!shouldCancel) {
            return false;
        }

        delete increasePositionRequests[_key];

        if (request.hasCollateralInETH) {
            _transferOutETHWithGasLimitFallbackToWeth(
                request.amountIn,
                payable(request.account)
            );
        } else {
            IERC20(request.path[0]).safeTransfer(
                request.account,
                request.amountIn
            );
        }

        _transferOutETHWithGasLimitFallbackToWeth(
            request.executionFee,
            _executionFeeReceiver
        );

        emit CancelIncreasePosition(
            request.account,
            request.path,
            request.indexToken,
            request.amountIn,
            request.minOut,
            request.sizeDelta,
            request.isLong,
            request.acceptablePrice,
            request.executionFee,
            block.number.sub(request.blockNumber),
            block.timestamp.sub(request.blockTime)
        );

        return true;
    }

    function executeDecreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        DecreasePositionRequest memory request = decreasePositionRequests[_key];
        // if the request was already executed or cancelled, return true so that the executeDecreasePositions loop will continue executing the next request
        if (request.account == address(0)) {
            return true;
        }

        bool shouldExecute = _validateExecution(
            request.blockNumber,
            request.blockTime,
            request.account
        );
        if (!shouldExecute) {
            return false;
        }

        delete decreasePositionRequests[_key];

        uint256 amountOut = _decreasePosition(
            request.account,
            request.path[0],
            request.indexToken,
            request.collateralDelta,
            request.sizeDelta,
            request.isLong,
            address(this),
            request.acceptablePrice
        );

        if (amountOut > 0) {
            if (request.path.length > 1) {
                IERC20(request.path[0]).safeTransfer(
                    addressesProvider.getVault(),
                    amountOut
                );
                amountOut = _swap(request.path, request.minOut, address(this));
            }

            if (request.withdrawETH) {
                _transferOutETHWithGasLimitFallbackToWeth(
                    amountOut,
                    payable(request.receiver)
                );
            } else {
                IERC20(request.path[request.path.length - 1]).safeTransfer(
                    request.receiver,
                    amountOut
                );
            }
        }

        _transferOutETHWithGasLimitFallbackToWeth(
            request.executionFee,
            _executionFeeReceiver
        );

        emit ExecuteDecreasePosition(
            request.account,
            request.path,
            request.indexToken,
            request.collateralDelta,
            request.sizeDelta,
            request.isLong,
            request.receiver,
            request.acceptablePrice,
            request.minOut,
            request.executionFee,
            block.number.sub(request.blockNumber),
            block.timestamp.sub(request.blockTime)
        );

        return true;
    }

    function cancelDecreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        DecreasePositionRequest memory request = decreasePositionRequests[_key];
        // if the request was already executed or cancelled, return true so that the executeDecreasePositions loop will continue executing the next request
        if (request.account == address(0)) {
            return true;
        }

        bool shouldCancel = _validateCancellation(
            request.blockNumber,
            request.blockTime,
            request.account
        );
        if (!shouldCancel) {
            return false;
        }

        delete decreasePositionRequests[_key];

        _transferOutETHWithGasLimitFallbackToWeth(
            request.executionFee,
            _executionFeeReceiver
        );

        emit CancelDecreasePosition(
            request.account,
            request.path,
            request.indexToken,
            request.collateralDelta,
            request.sizeDelta,
            request.isLong,
            request.receiver,
            request.acceptablePrice,
            request.minOut,
            request.executionFee,
            block.number.sub(request.blockNumber),
            block.timestamp.sub(request.blockTime)
        );

        return true;
    }

    function getRequestKey(
        address _account,
        uint256 _index
    ) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_account, _index));
    }

    function getIncreasePositionRequestPath(
        bytes32 _key
    ) public view returns (address[] memory) {
        IncreasePositionRequest memory request = increasePositionRequests[_key];
        return request.path;
    }

    function getDecreasePositionRequestPath(
        bytes32 _key
    ) public view returns (address[] memory) {
        DecreasePositionRequest memory request = decreasePositionRequests[_key];
        return request.path;
    }

    function _validateExecution(
        uint256 _positionBlockNumber,
        uint256 _positionBlockTime,
        address _account
    ) internal view returns (bool) {
        require(
            block.timestamp < _positionBlockTime.add(maxTimeDelay),
            "PositionRouter: request has expired"
        );

        return
            _validateCancellation(
                _positionBlockNumber,
                _positionBlockTime,
                _account
            );
    }

    function _validateCancellation(
        uint256 _positionBlockNumber,
        uint256 _positionBlockTime,
        address _account
    ) internal view returns (bool) {
        if (isPositionKeeper[msg.sender]) {
            return
                _positionBlockNumber.add(minBlockDelayKeeper) <= block.number;
        }

        require(
            msg.sender == _account &&
                _positionBlockTime.add(minTimeDelayPublic) <= block.timestamp,
            "PositionRouter: forbidden"
        );
        return true;
    }

    function _createIncreasePosition(
        address _account,
        address[] memory _path,
        address _indexToken,
        uint256 _amountIn,
        uint256 _minOut,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 _executionFee,
        bool _hasCollateralInETH
    ) internal {
        uint256 index = increasePositionsIndex[_account].add(1);
        increasePositionsIndex[_account] = index;

        IncreasePositionRequest memory request = IncreasePositionRequest(
            _account,
            _path,
            _indexToken,
            _amountIn,
            _minOut,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            _executionFee,
            block.number,
            block.timestamp,
            _hasCollateralInETH
        );

        bytes32 key = getRequestKey(_account, index);
        increasePositionRequests[key] = request;

        increasePositionRequestKeys.push(key);

        emit CreateIncreasePosition(
            _account,
            _path,
            _indexToken,
            _amountIn,
            _minOut,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            _executionFee,
            index,
            block.number,
            block.timestamp,
            tx.gasprice
        );
    }

    function _createDecreasePosition(
        address _account,
        address[] memory _path,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _acceptablePrice,
        uint256 _minOut,
        uint256 _executionFee,
        bool _withdrawETH
    ) internal {
        uint256 index = decreasePositionsIndex[_account].add(1);
        decreasePositionsIndex[_account] = index;

        DecreasePositionRequest memory request = DecreasePositionRequest(
            _account,
            _path,
            _indexToken,
            _collateralDelta,
            _sizeDelta,
            _isLong,
            _receiver,
            _acceptablePrice,
            _minOut,
            _executionFee,
            block.number,
            block.timestamp,
            _withdrawETH
        );

        bytes32 key = getRequestKey(_account, index);
        decreasePositionRequests[key] = request;

        decreasePositionRequestKeys.push(key);

        emit CreateDecreasePosition(
            _account,
            _path,
            _indexToken,
            _collateralDelta,
            _sizeDelta,
            _isLong,
            _receiver,
            _acceptablePrice,
            _minOut,
            _executionFee,
            index,
            block.number,
            block.timestamp
        );
    }
}
        

contracts/dependencies/openzeppelin/contracts/Address.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

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

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{value: amount}("");
        require(
            success,
            "Address: unable to send value, recipient may have reverted"
        );
    }

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

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

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

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

contracts/dependencies/openzeppelin/contracts/Context.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

contracts/dependencies/openzeppelin/contracts/IERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

contracts/dependencies/openzeppelin/contracts/Ownable.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";

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

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

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

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

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

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

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

contracts/dependencies/openzeppelin/contracts/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

        _;

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

contracts/dependencies/openzeppelin/contracts/SafeERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";

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

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

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

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

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

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

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

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

contracts/dependencies/openzeppelin/contracts/SafeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

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

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

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

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

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

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

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

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

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

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

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

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

contracts/interfaces/IAddressesProvider.sol

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

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

    function getPhlp() external view returns (address);

    function getPhlpManager() external view returns (address);

    function getVault() external view returns (address);

    function getVaultConfigurator() external view returns (address);

    function getRouter() external view returns (address);

    function getOrderBook() external view returns (address);

    function getPositionManager() external view returns (address);

    function getPositionRouter() external view returns (address);

    function getPriceOracle() external view returns (address);

    function getShortsTracker() external view returns (address);

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

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

contracts/interfaces/IBasePositionManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

contracts/interfaces/IPhamePriceOracle.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

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

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

    function setSpreadBps(address _token, uint256 _spreadBps) external;

    function setSpreadThresholdBps(uint256 _spreadThresholdBps) external;

    function setPriceSampleSpace(uint256 _priceSampleSpace) external;

    function setMaxStrictPriceDeviation(
        uint256 _maxStrictPriceDeviation
    ) external;

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

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

contracts/interfaces/IPositionRouter.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPositionRouter {
    event CreateIncreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 amountIn,
        uint256 minOut,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 index,
        uint256 blockNumber,
        uint256 blockTime,
        uint256 gasPrice
    );

    event ExecuteIncreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 amountIn,
        uint256 minOut,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CancelIncreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 amountIn,
        uint256 minOut,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CreateDecreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 minOut,
        uint256 executionFee,
        uint256 index,
        uint256 blockNumber,
        uint256 blockTime
    );

    event ExecuteDecreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 minOut,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CancelDecreasePosition(
        address indexed account,
        address[] path,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 minOut,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event SetPositionKeeper(address indexed account, bool isActive);
    event SetMinExecutionFee(uint256 minExecutionFee);
    event SetIsLeverageEnabled(bool isLeverageEnabled);
    event SetDelayValues(uint256 minBlockDelayKeeper, uint256 maxTimeDelay);
    event SetRequestKeysStartValues(
        uint256 increasePositionRequestKeysStart,
        uint256 decreasePositionRequestKeysStart
    );

    function increasePositionRequestKeys(
        uint256 idx
    ) external view returns (bytes32);

    function decreasePositionRequestKeys(
        uint256 idx
    ) external view returns (bytes32);

    function increasePositionRequestKeysStart() external view returns (uint256);

    function decreasePositionRequestKeysStart() external view returns (uint256);

    function executeIncreasePositions(
        uint256 _count,
        address payable _executionFeeReceiver
    ) external;

    function executeDecreasePositions(
        uint256 _count,
        address payable _executionFeeReceiver
    ) external;
}
          

contracts/interfaces/IRouter.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IRouter {
    event Swap(
        address account,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut
    );

    function pluginTransfer(
        address _token,
        address _account,
        address _receiver,
        uint256 _amount
    ) external;

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

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

    function swap(
        address[] memory _path,
        uint256 _amountIn,
        uint256 _minOut,
        address _receiver
    ) external;
}
          

contracts/interfaces/IShortsTracker.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

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

contracts/interfaces/IVault.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

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

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

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

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

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

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

    function addressesProvider() external view returns (IAddressesProvider);

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

    function setVaultConfig(
        DataTypes.VaultConfig calldata vaultConfig
    ) external;

    function allWhitelistedTokensLength() external view returns (uint256);

    function totalTokenWeights() external view returns (uint256);

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

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

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

    function clearTokenConfig(address _token) external;

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

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

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

    function setUsdphAmount(address _token, uint256 _amount) external;

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

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

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

    function directPoolDeposit(address _token) external;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

contracts/interfaces/IVaultConfigurator.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

interface IVaultConfigurator {
    function setIsLeverageEnabled(bool _isLeverageEnabled) external;

    function setStakingBps(uint256 _stakingBps) external;

    function setUsdphAmount(address _token, uint256 _amount) external;

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

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

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

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

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

contracts/interfaces/IWETH.sol

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

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256) external;

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

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

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

contracts/protocol/core/BasePositionManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

import "../../dependencies/openzeppelin/contracts/Ownable.sol";
import "../../dependencies/openzeppelin/contracts/SafeMath.sol";
import "../../dependencies/openzeppelin/contracts/Address.sol";
import "../../dependencies/openzeppelin/contracts/ReentrancyGuard.sol";
import "../../dependencies/openzeppelin/contracts/IERC20.sol";
import "../../dependencies/openzeppelin/contracts/SafeERC20.sol";
import "../../interfaces/IAddressesProvider.sol";
import "../../interfaces/IPhamePriceOracle.sol";
import "../../interfaces/IWETH.sol";
import "../../interfaces/IRouter.sol";
import "../../interfaces/IVault.sol";
import "../../interfaces/IVaultConfigurator.sol";
import "../../interfaces/IShortsTracker.sol";
import "../../interfaces/IBasePositionManager.sol";

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

    uint256 public constant MAX_MIN_TIME_DELAY_PUBLIC = 600;
    uint256 public constant BASIS_POINTS_DIVISOR = 10000;
    uint256 public constant MAX_DEPOSIT_FEE = 100;
    uint256 public constant MAX_INCREASE_POSITION_BUFFER_BPS = 10000;

    IAddressesProvider public immutable addressesProvider;
    address public immutable weth;

    uint256 public ethTransferGasLimit = 500 * 1000;
    uint256 public minTimeDelayPublic;
    // to prevent using the deposit and withdrawal of collateral as a zero fee swap,
    // there is a small depositFee charged if a collateral deposit results in the decrease
    // of leverage for an existing position
    // increasePositionBufferBps allows for a small amount of decrease of leverage
    uint256 public depositFee;
    uint256 public increasePositionBufferBps = 100;

    mapping(address => uint256) public feeReserves;

    constructor(
        IAddressesProvider addressesProvider_,
        address _weth,
        uint256 _depositFee
    ) Ownable() {
        require(
            address(addressesProvider_) != address(0),
            "BasePositionManager: addressesProvider is zero address"
        );
        require(
            _weth != address(0),
            "BasePositionManager: weth is zero address"
        );
        require(
            _depositFee <= MAX_DEPOSIT_FEE,
            "BasePositionManager: depositFee is too high"
        );
        addressesProvider = addressesProvider_;
        weth = _weth;
        depositFee = _depositFee;
    }

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

    function setEthTransferGasLimit(
        uint256 _ethTransferGasLimit
    ) external onlyOwner {
        ethTransferGasLimit = _ethTransferGasLimit;
        emit SetEthTransferGasLimit(_ethTransferGasLimit);
    }

    function setMinTimeDelayPublic(
        uint256 _minTimeDelayPublic
    ) external onlyOwner {
        require(
            _minTimeDelayPublic <= MAX_MIN_TIME_DELAY_PUBLIC,
            "BasePositionManager: minTimeDelayPublic is too high"
        );
        minTimeDelayPublic = _minTimeDelayPublic;
        emit SetMinTimeDelayPublic(_minTimeDelayPublic);
    }

    function setDepositFee(uint256 _depositFee) external onlyOwner {
        require(
            _depositFee <= MAX_DEPOSIT_FEE,
            "BasePositionManager: depositFee is too high"
        );
        depositFee = _depositFee;
        emit SetDepositFee(_depositFee);
    }

    function setIncreasePositionBufferBps(
        uint256 _increasePositionBufferBps
    ) external onlyOwner {
        require(
            _increasePositionBufferBps <= MAX_INCREASE_POSITION_BUFFER_BPS,
            "BasePositionManager: increasePositionBufferBps is too high"
        );
        increasePositionBufferBps = _increasePositionBufferBps;
        emit SetIncreasePositionBufferBps(_increasePositionBufferBps);
    }

    function withdrawFees(address _token, address _receiver) external override {
        require(
            msg.sender == addressesProvider.getPhlpManager(),
            "BasePositionManager: Only PhlpManager can withdraw fee"
        );

        uint256 amount = feeReserves[_token];
        if (amount == 0) {
            return;
        }

        feeReserves[_token] = 0;
        IERC20(_token).safeTransfer(_receiver, amount);

        emit WithdrawFees(_token, _receiver, amount);
    }

    function _increasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _price
    ) internal {
        uint256 markPrice = IPhamePriceOracle(
            addressesProvider.getPriceOracle()
        ).getPrice(_indexToken, _isLong);
        if (_isLong) {
            require(
                markPrice <= _price,
                "BasePositionManager: mark price higher than limit"
            );
        } else {
            require(
                markPrice >= _price,
                "BasePositionManager: mark price lower than limit"
            );
        }

        IShortsTracker(addressesProvider.getShortsTracker())
            .updateGlobalShortData(
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                _sizeDelta,
                markPrice,
                true
            );
        IRouter(addressesProvider.getRouter()).pluginIncreasePosition(
            _account,
            _collateralToken,
            _indexToken,
            _sizeDelta,
            _isLong
        );
    }

    function _decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _price
    ) internal returns (uint256) {
        uint256 markPrice = IPhamePriceOracle(
            addressesProvider.getPriceOracle()
        ).getPrice(_indexToken, !_isLong);
        if (_isLong) {
            require(
                markPrice >= _price,
                "BasePositionManager: mark price lower than limit"
            );
        } else {
            require(
                markPrice <= _price,
                "BasePositionManager: mark price higher than limit"
            );
        }

        IShortsTracker(addressesProvider.getShortsTracker())
            .updateGlobalShortData(
                _account,
                _collateralToken,
                _indexToken,
                _isLong,
                _sizeDelta,
                markPrice,
                false
            );
        uint256 amountOut = IRouter(addressesProvider.getRouter())
            .pluginDecreasePosition(
                _account,
                _collateralToken,
                _indexToken,
                _collateralDelta,
                _sizeDelta,
                _isLong,
                _receiver
            );

        return amountOut;
    }

    function _swap(
        address[] memory _path,
        uint256 _minOut,
        address _receiver
    ) internal returns (uint256) {
        if (_path.length == 2) {
            return _vaultSwap(_path[0], _path[1], _minOut, _receiver);
        }
        revert("BasePositionManager: invalid _path.length");
    }

    function _vaultSwap(
        address _tokenIn,
        address _tokenOut,
        uint256 _minOut,
        address _receiver
    ) internal returns (uint256) {
        uint256 amountOut = IVault(addressesProvider.getVault()).swap(
            _tokenIn,
            _tokenOut,
            _receiver
        );
        require(
            amountOut >= _minOut,
            "BasePositionManager: insufficient amountOut"
        );
        return amountOut;
    }

    function _transferInETH() internal {
        if (msg.value != 0) {
            IWETH(weth).deposit{value: msg.value}();
        }
    }

    function _transferOutETHWithGasLimitFallbackToWeth(
        uint256 _amountOut,
        address payable _receiver
    ) internal {
        IWETH _weth = IWETH(weth);
        _weth.withdraw(_amountOut);

        (bool success /* bytes memory data */, ) = _receiver.call{
            value: _amountOut,
            gas: ethTransferGasLimit
        }("");

        if (success) {
            return;
        }

        // if the transfer failed, re-wrap the token and send it to the receiver
        _weth.deposit{value: _amountOut}();
        _weth.transfer(address(_receiver), _amountOut);
    }

    function _collectFees(
        address _account,
        address[] memory _path,
        uint256 _amountIn,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) internal returns (uint256) {
        bool shouldDeductFee = _shouldDeductFee(
            _account,
            _path,
            _amountIn,
            _indexToken,
            _isLong,
            _sizeDelta
        );

        if (shouldDeductFee) {
            uint256 afterFeeAmount = _amountIn
                .mul(BASIS_POINTS_DIVISOR.sub(depositFee))
                .div(BASIS_POINTS_DIVISOR);
            uint256 feeAmount = _amountIn.sub(afterFeeAmount);
            address feeToken = _path[_path.length - 1];
            feeReserves[feeToken] = feeReserves[feeToken].add(feeAmount);
            return afterFeeAmount;
        }

        return _amountIn;
    }

    function _shouldDeductFee(
        address _account,
        address[] memory _path,
        uint256 _amountIn,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) internal view returns (bool) {
        // if the position is a short, do not charge a fee
        if (!_isLong) {
            return false;
        }

        // if the position size is not increasing, this is a collateral deposit
        if (_sizeDelta == 0) {
            return true;
        }

        address collateralToken = _path[_path.length - 1];

        IVault vault = IVault(addressesProvider.getVault());
        (uint256 size, uint256 collateral, , , , , , ) = vault.getPosition(
            _account,
            collateralToken,
            _indexToken,
            _isLong
        );

        // if there is no existing position, do not charge a fee
        if (size == 0) {
            return false;
        }

        uint256 nextSize = size.add(_sizeDelta);
        uint256 collateralDelta = vault.tokenToUsdMin(
            collateralToken,
            _amountIn
        );
        uint256 nextCollateral = collateral.add(collateralDelta);

        uint256 prevLeverage = size.mul(BASIS_POINTS_DIVISOR).div(collateral);
        // allow for a maximum of a increasePositionBufferBps decrease since there might be some swap fees taken from the collateral
        uint256 nextLeverage = nextSize
            .mul(BASIS_POINTS_DIVISOR + increasePositionBufferBps)
            .div(nextCollateral);

        // deduct a fee if the leverage is decreased
        return nextLeverage < prevLeverage;
    }
}
          

contracts/protocol/libraries/types/DataTypes.sol

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

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

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

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

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

Compiler Settings

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

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"addressesProvider_","internalType":"contract IAddressesProvider"},{"type":"address","name":"_weth","internalType":"address"},{"type":"uint256","name":"_depositFee","internalType":"uint256"},{"type":"uint256","name":"_minExecutionFee","internalType":"uint256"}]},{"type":"event","name":"CancelDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","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":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockGap","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeGap","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CancelIncreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","internalType":"address[]","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockGap","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeGap","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","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":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockTime","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateIncreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","internalType":"address[]","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockTime","internalType":"uint256","indexed":false},{"type":"uint256","name":"gasPrice","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","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":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockGap","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeGap","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteIncreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address[]","name":"path","internalType":"address[]","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","internalType":"uint256","indexed":false},{"type":"uint256","name":"minOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"uint256","name":"acceptablePrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"blockGap","internalType":"uint256","indexed":false},{"type":"uint256","name":"timeGap","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SetDelayValues","inputs":[{"type":"uint256","name":"minBlockDelayKeeper","internalType":"uint256","indexed":false},{"type":"uint256","name":"maxTimeDelay","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetDepositFee","inputs":[{"type":"uint256","name":"depositFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetEthTransferGasLimit","inputs":[{"type":"uint256","name":"ethTransferGasLimit","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetIncreasePositionBufferBps","inputs":[{"type":"uint256","name":"increasePositionBufferBps","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetIsLeverageEnabled","inputs":[{"type":"bool","name":"isLeverageEnabled","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetMinExecutionFee","inputs":[{"type":"uint256","name":"minExecutionFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetMinTimeDelayPublic","inputs":[{"type":"uint256","name":"minTimeDelayPublic","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetPositionKeeper","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetRequestKeysStartValues","inputs":[{"type":"uint256","name":"increasePositionRequestKeysStart","internalType":"uint256","indexed":false},{"type":"uint256","name":"decreasePositionRequestKeysStart","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawFees","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"amount","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":"MAX_DEPOSIT_FEE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_INCREASE_POSITION_BUFFER_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_MAX_TIME_DELAY","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_MIN_BLOCK_DELAY_KEEPER","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_MIN_EXECUTION_FEE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_MIN_TIME_DELAY_PUBLIC","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAddressesProvider"}],"name":"addressesProvider","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelDecreasePosition","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelIncreasePosition","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createDecreasePosition","inputs":[{"type":"address[]","name":"_path","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":"uint256","name":"_acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"uint256","name":"_executionFee","internalType":"uint256"},{"type":"bool","name":"_withdrawETH","internalType":"bool"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createIncreasePosition","inputs":[{"type":"address[]","name":"_path","internalType":"address[]"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_amountIn","internalType":"uint256"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"_executionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createIncreasePositionETH","inputs":[{"type":"address[]","name":"_path","internalType":"address[]"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"_executionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"decreasePositionRequestKeys","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"decreasePositionRequestKeysStart","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","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":"uint256","name":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"minOut","internalType":"uint256"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"uint256","name":"blockNumber","internalType":"uint256"},{"type":"uint256","name":"blockTime","internalType":"uint256"},{"type":"bool","name":"withdrawETH","internalType":"bool"}],"name":"decreasePositionRequests","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"decreasePositionsIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"depositFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ethTransferGasLimit","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"executeDecreasePosition","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeDecreasePositions","inputs":[{"type":"uint256","name":"_endIndex","internalType":"uint256"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"executeIncreasePosition","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeIncreasePositions","inputs":[{"type":"uint256","name":"_endIndex","internalType":"uint256"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeReserves","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getDecreasePositionRequestPath","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getIncreasePositionRequestPath","inputs":[{"type":"bytes32","name":"_key","internalType":"bytes32"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRequestKey","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"uint256","name":"_index","internalType":"uint256"}]},{"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"}],"name":"getRequestQueueLengths","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"increasePositionBufferBps","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"increasePositionRequestKeys","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"increasePositionRequestKeysStart","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"minOut","internalType":"uint256"},{"type":"uint256","name":"sizeDelta","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"uint256","name":"blockNumber","internalType":"uint256"},{"type":"uint256","name":"blockTime","internalType":"uint256"},{"type":"bool","name":"hasCollateralInETH","internalType":"bool"}],"name":"increasePositionRequests","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"increasePositionsIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPositionKeeper","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxTimeDelay","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minBlockDelayKeeper","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minExecutionFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minTimeDelayPublic","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDelayValues","inputs":[{"type":"uint256","name":"_minBlockDelayKeeper","internalType":"uint256"},{"type":"uint256","name":"_maxTimeDelay","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDepositFee","inputs":[{"type":"uint256","name":"_depositFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEthTransferGasLimit","inputs":[{"type":"uint256","name":"_ethTransferGasLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setIncreasePositionBufferBps","inputs":[{"type":"uint256","name":"_increasePositionBufferBps","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinExecutionFee","inputs":[{"type":"uint256","name":"_minExecutionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinTimeDelayPublic","inputs":[{"type":"uint256","name":"_minTimeDelayPublic","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPositionKeeper","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"bool","name":"_isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequestKeysStartValues","inputs":[{"type":"uint256","name":"_increasePositionRequestKeysStart","internalType":"uint256"},{"type":"uint256","name":"_decreasePositionRequestKeysStart","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"weth","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFees","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60c06040526207a12060025560646005553480156200001d57600080fd5b50604051620059cf380380620059cf833981810160405260808110156200004357600080fd5b508051602082015160408301516060909301516001600090815592939192849084908490620000716200021e565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b038316620001065760405162461bcd60e51b8152600401808060200182810382526036815260200180620059436036913960400191505060405180910390fd5b6001600160a01b0382166200014d5760405162461bcd60e51b81526004018080602001828103825260298152602001806200591a6029913960400191505060405180910390fd5b60648111156200018f5760405162461bcd60e51b815260040180806020018281038252602b81526020018062005979602b913960400191505060405180910390fd5b6001600160601b0319606093841b81166080529190921b1660a05260045569d3c21bcecceda1000000811115620001f85760405162461bcd60e51b815260040180806020018281038252602b815260200180620059a4602b913960400191505060405180910390fd5b6007555050306000908152600e60205260409020805460ff191660011790555062000222565b3390565b60805160601c60a05160601c615679620002a1600039806102f8528061148052806121e052806130ae5280613c575280613e7d5250806110ff5280611c8b5280612cfe5280612e4c528061318352806137a452806139315280613a46528061436752806144f5528061460a5280614b585280614ce952506156796000f3fe6080604052600436106102e85760003560e01c8063633451de11610190578063cb0269c9116100dc578063f255527811610095578063f3883d8b1161006f578063f3883d8b14610d2c578063fa44457714610d65578063faf990f314610d98578063fc2cee6214610e2657610356565b8063f255527814610c83578063f2cea6a514610cbe578063f2fde38b14610cf957610356565b8063cb0269c914610a79578063ceed2cc114610a8e578063d467a4ae14610b60578063e70dd2fc14610b75578063e8caee1c14610c59578063ec2a1bf214610c6e57610356565b806395e9bbd7116101495780639b578620116101235780639b57862014610a0a578063a4e7684f14610a1f578063c6d87dd514610a4f578063c72c4d1014610a6457610356565b806395e9bbd71461099257806398d1e03a146109bc5780639a208100146109d157610356565b8063633451de146108f657806363ae21031461092957806367a527931461093e578063715018a6146109535780638da5cb5b146109685780638f6494941461097d57610356565b80632d79cf421161024f5780633fc8cef3116102085780635841fcaa116101e25780635841fcaa146107f55780635d5c22e81461080a57806360a362e21461088457806362f8a3fe146108bd57610356565b80633fc8cef3146107705780634278555f146107a1578063490ae210146107cb57610356565b80632d79cf421461067e578063308aa81f146106935780633422ead1146106c357806336eba48a146106fe5780633a2a80c7146107315780633a9b52ad1461074657610356565b80631ce9cb8f116102a15780631ce9cb8f146104d95780631f2851061461050c578063225fc9fd146105b8578063233bfe3b146105f157806327b42c0f1461061b5780632b73fb181461065457610356565b8063042259541461035b5780630d4d003d14610397578063126082cf146103e4578063133e5b17146103f957806315de6386146103e45780631bca8cf0146104c457610356565b3661035657336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103545760405162461bcd60e51b815260040180806020018281038252602381526020018061556d6023913960400191505060405180910390fd5b005b600080fd5b34801561036757600080fd5b506103856004803603602081101561037e57600080fd5b5035610e50565b60408051918252519081900360200190f35b3480156103a357600080fd5b506103d0600480360360408110156103ba57600080fd5b50803590602001356001600160a01b0316610e71565b604080519115158252519081900360200190f35b3480156103f057600080fd5b50610385611361565b610354600480360360e081101561040f57600080fd5b81019060208101813564010000000081111561042a57600080fd5b82018360208201111561043c57600080fd5b8035906020019184602083028401116401000000008311171561045e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b0383351693505050602081013590604081013590606081013515159060808101359060a00135611367565b3480156104d057600080fd5b50610385611550565b3480156104e557600080fd5b50610385600480360360208110156104fc57600080fd5b50356001600160a01b0316611556565b34801561051857600080fd5b506105366004803603602081101561052f57600080fd5b5035611568565b604051808d6001600160a01b031681526020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182151581526020019c5050505050505050505050505060405180910390f35b3480156105c457600080fd5b506103d0600480360360408110156105db57600080fd5b50803590602001356001600160a01b03166115d4565b3480156105fd57600080fd5b506103546004803603602081101561061457600080fd5b5035611974565b34801561062757600080fd5b506103d06004803603604081101561063e57600080fd5b50803590602001356001600160a01b0316611a52565b34801561066057600080fd5b506103546004803603602081101561067757600080fd5b5035611e53565b34801561068a57600080fd5b50610385611f31565b34801561069f57600080fd5b50610354600480360360408110156106b657600080fd5b5080359060200135611f37565b3480156106cf57600080fd5b50610354600480360360408110156106e657600080fd5b506001600160a01b0381351690602001351515612064565b34801561070a57600080fd5b506103d06004803603602081101561072157600080fd5b50356001600160a01b0316612126565b34801561073d57600080fd5b5061038561213b565b34801561075257600080fd5b506103546004803603602081101561076957600080fd5b5035612141565b34801561077c57600080fd5b506107856121de565b604080516001600160a01b039092168252519081900360200190f35b3480156107ad57600080fd5b50610385600480360360208110156107c457600080fd5b5035612202565b3480156107d757600080fd5b50610354600480360360208110156107ee57600080fd5b5035612212565b34801561080157600080fd5b506103856122ef565b34801561081657600080fd5b506108346004803603602081101561082d57600080fd5b50356122f5565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610870578181015183820152602001610858565b505050509050019250505060405180910390f35b34801561089057600080fd5b506103d0600480360360408110156108a757600080fd5b50803590602001356001600160a01b0316612419565b3480156108c957600080fd5b50610385600480360360408110156108e057600080fd5b506001600160a01b03813516906020013561279f565b34801561090257600080fd5b506103856004803603602081101561091957600080fd5b50356001600160a01b03166127e5565b34801561093557600080fd5b506103856127f7565b34801561094a57600080fd5b506103856127fd565b34801561095f57600080fd5b50610354612803565b34801561097457600080fd5b506107856128af565b34801561098957600080fd5b506103856128be565b34801561099e57600080fd5b50610834600480360360208110156109b557600080fd5b50356128cc565b3480156109c857600080fd5b506103856129e2565b3480156109dd57600080fd5b50610354600480360360408110156109f457600080fd5b50803590602001356001600160a01b03166129e8565b348015610a1657600080fd5b50610385612bc5565b348015610a2b57600080fd5b5061035460048036036040811015610a4257600080fd5b5080359060200135612bcb565b348015610a5b57600080fd5b50610385612cf7565b348015610a7057600080fd5b50610785612cfc565b348015610a8557600080fd5b50610385612d20565b6103546004803603610100811015610aa557600080fd5b810190602081018135640100000000811115610ac057600080fd5b820183602082011115610ad257600080fd5b80359060200191846020830284011164010000000083111715610af457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b0383351693505050602081013590604081013590606081013590608081013515159060a08101359060c00135612d26565b348015610b6c57600080fd5b50610385612f8b565b6103546004803603610140811015610b8c57600080fd5b810190602081018135640100000000811115610ba757600080fd5b820183602082011115610bb957600080fd5b80359060200191846020830284011164010000000083111715610bdb57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505081356001600160a01b0390811693506020830135926040810135925060608101351515916080820135169060a08101359060c08101359060e08101359061010001351515612f90565b348015610c6557600080fd5b50610385613175565b348015610c7a57600080fd5b5061038561317b565b348015610c8f57600080fd5b5061035460048036036040811015610ca657600080fd5b506001600160a01b0381358116916020013516613181565b348015610cca57600080fd5b50610cd36132e3565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610d0557600080fd5b5061035460048036036020811015610d1c57600080fd5b50356001600160a01b03166132f5565b348015610d3857600080fd5b5061035460048036036040811015610d4f57600080fd5b50803590602001356001600160a01b03166133f8565b348015610d7157600080fd5b5061038560048036036020811015610d8857600080fd5b50356001600160a01b03166135d4565b348015610da457600080fd5b50610dc260048036036020811015610dbb57600080fd5b50356135e6565b604080516001600160a01b039c8d1681529a909b1660208b0152898b01989098526060890196909652608088019490945291151560a087015260c086015260e085015261010084015261012083015215156101408201529051908190036101600190f35b348015610e3257600080fd5b5061035460048036036020811015610e4957600080fd5b5035613650565b600a8181548110610e6057600080fd5b600091825260209091200154905081565b600060026000541415610eb9576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260126020908152604080832081516101a08101835281546001600160a01b031681526001820180548451818702810187019095528085529194929385840193909290830182828015610f3e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f20575b505050918352505060028201546001600160a01b0390811660208301526003830154604083015260048301546060830152600583015460ff8082161515608085015261010091829004831660a0850152600685015460c0850152600785015460e08501526008850154918401919091526009840154610120840152600a840154610140840152600b90930154909216151561016090910152815191925016610fea576001915050611356565b60006110058261014001518361016001518460000151613736565b90508061101757600092505050611356565b600085815260126020526040812080546001600160a01b031916815590611041600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820180546001600160a81b031916905560068201819055600782018190556008820181905560098201819055600a8201819055600b909101805460ff191690558251602084015180516110e492919084906110bd57fe5b60200260200101518560400151866060015187608001518860a00151308a60e0015161379f565b9050801561120b57600183602001515111156111cc576111b57f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d602081101561118057600080fd5b50516020850151805184919060009061119557fe5b60200260200101516001600160a01b0316613b7e9092919063ffffffff16565b6111c9836020015184610100015130613bd5565b90505b826101800151156111ea576111e5818460c00151613c53565b61120b565b61120b8360c001518285602001516001876020015151038151811061119557fe5b61121a83610120015186613c53565b82600001516001600160a01b03167f21435c5b618d77ff3657140cd3318e2cffaebc5e0e1b7318f56a9ba4044c3ed284602001518560400151866060015187608001518860a001518960c001518a60e001518b61010001518c61012001516112908e610140015143613e1890919063ffffffff16565b6101608f01516112a1904290613e18565b60405180806020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182810382528d818151815260200191508051906020019060200280838360005b83811015611331578181015183820152602001611319565b505050509050019c5050505050505050505050505060405180910390a2600193505050505b600160005592915050565b61271081565b600260005414156113ad576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b60026000556007548110156113f35760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b803410156114325760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b865160011480611443575086516002145b61147e5760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876000815181106114b557fe5b60200260200101516001600160a01b031614611518576040805162461bcd60e51b815260206004820152601d60248201527f506f736974696f6e526f757465723a20696e76616c6964205f70617468000000604482015290519081900360640190fd5b611520613e75565b600061152c3483613e18565b9050611541338989848a8a8a8a8a6001613ef2565b50506001600055505050505050565b600d5481565b60066020526000908152604090205481565b6012602052600090815260409020805460028201546003830154600484015460058501546006860154600787015460088801546009890154600a8a0154600b909a01546001600160a01b03998a169a988a16999798969760ff808816986101009098049091169691168c565b60006002600054141561161c576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260106020908152604080832081516101808101835281546001600160a01b0316815260018201805484518187028101870190955280855291949293858401939092908301828280156116a157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611683575b505050918352505060028201546001600160a01b039081166020830152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b9093015490921615156101409091015281519192501661173d576001915050611356565b600061175882610120015183610140015184600001516141c2565b90508061176a57600092505050611356565b600085815260106020526040812080546001600160a01b031916815590611794600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560068201805460ff19908116909155600783018290556008830182905560098301829055600a830191909155600b90910180549091169055610160820151156118185761181382606001518360000151613c53565b611836565b61183682600001518360600151846020015160008151811061119557fe5b61184582610100015185613c53565b81600001516001600160a01b03167f35b638e650e2328786fb405bd69d2083dbedc018d086662e74b775b4f1dae4bf83602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516118b58c610120015143613e1890919063ffffffff16565b6101408d01516118c6904290613e18565b60405180806020018b6001600160a01b031681526020018a8152602001898152602001888152602001871515815260200186815260200185815260200184815260200183815260200182810382528c818151815260200191508051906020019060200280838360005b8381101561194757818101518382015260200161192f565b505050509050019b50505050505050505050505060405180910390a2600192505050600160005592915050565b61197c614280565b6001600160a01b031661198d6128af565b6001600160a01b0316146119d6576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b612710811115611a175760405162461bcd60e51b815260040180806020018281038252603a8152602001806154ce603a913960400191505060405180910390fd5b60058190556040805182815290517f21167d0d4661af93817ebce920f18986eed3d75d5e1c03f2aed05efcbafbc4529181900360200190a150565b600060026000541415611a9a576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260106020908152604080832081516101808101835281546001600160a01b031681526001820180548451818702810187019095528085529194929385840193909290830182828015611b1f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b01575b505050918352505060028201546001600160a01b039081166020830152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b90930154909216151561014090910152815191925016611bbb576001915050611356565b6000611bd68261012001518361014001518460000151613736565b905080611be857600092505050611356565b600085815260106020526040812080546001600160a01b031916815590611c12600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560068201805460ff19908116909155600783018290556008830182905560098301829055600a830191909155600b90910180549091169055606082015115611d965760008260600151905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015611ce257600080fd5b505afa158015611cf6573d6000803e3d6000fd5b505050506040513d6020811015611d0c57600080fd5b505160208501515190915060011015611d4f57611d39818560600151866020015160008151811061119557fe5b611d4c8460200151856080015130613bd5565b91505b6000611d73856000015186602001518588604001518960c001518a60a00151614284565b9050611d92828287602001516001896020015151038151811061119557fe5b5050505b815160208301518051611dd49291906000198101908110611db357fe5b602002602001015184604001518560a001518660c001518760e00151614363565b611de382610100015185613c53565b81600001516001600160a01b03167f1be316b94d38c07bd41cdb4913772d0a0a82802786a2f8b657b6e85dbcdfc64183602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516118b58c610120015143613e1890919063ffffffff16565b611e5b614280565b6001600160a01b0316611e6c6128af565b6001600160a01b031614611eb5576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b610258811115611ef65760405162461bcd60e51b81526004018080602001828103825260338152602001806153fe6033913960400191505060405180910390fd5b60038190556040805182815290517fbd7411e312e9c7c95b6798503250129c3b613975a11dc36e76f469c5b8e8bcd59181900360200190a150565b60025481565b611f3f614280565b6001600160a01b0316611f506128af565b6001600160a01b031614611f99576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b600a54821115611fda5760405162461bcd60e51b815260040180806020018281038252603c815260200180615314603c913960400191505060405180910390fd5b600b5481111561201b5760405162461bcd60e51b815260040180806020018281038252603c815260200180615531603c913960400191505060405180910390fd5b600c829055600d819055604080518381526020810183905281517febb0f666150f4be5b60c45df8f3e49992510b0128027fe58eea6110f296493bc929181900390910190a15050565b61206c614280565b6001600160a01b031661207d6128af565b6001600160a01b0316146120c6576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600e6020908152604091829020805460ff1916851515908117909155825190815291517ffbabc02389290a451c6e600d05bf9887b99bfad39d8e1237e4e3df042e4941fe9281900390910190a25050565b600e6020526000908152604090205460ff1681565b60035481565b612149614280565b6001600160a01b031661215a6128af565b6001600160a01b0316146121a3576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b60028190556040805182815290517f4d371d598d3a13f99ce992a17975bbaf1e1c256e072ec7d2f93ce88e40d9ba1c9181900360200190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b600b8181548110610e6057600080fd5b61221a614280565b6001600160a01b031661222b6128af565b6001600160a01b031614612274576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b60648111156122b45760405162461bcd60e51b815260040180806020018281038252602b8152602001806153d3602b913960400191505060405180910390fd5b60048190556040805182815290517f974fd3c1fcb4653dfc4fb740c4c692cd212d55c28f163f310128cb64d83006759181900360200190a150565b60085481565b600081815260126020908152604080832081516101a08101835281546001600160a01b03168152600182018054845181870281018701909552808552606096959294858401939092919083018282801561237857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161235a575b505050918352505060028201546001600160a01b039081166020808401919091526003840154604084015260048401546060840152600584015460ff808216151560808601526101009182900490931660a0850152600685015460c0850152600785015460e08501526008850154908401526009840154610120840152600a840154610140840152600b909301541615156101609091015201519392505050565b600060026000541415612461576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260126020908152604080832081516101a08101835281546001600160a01b0316815260018201805484518187028101870190955280855291949293858401939092908301828280156124e657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116124c8575b505050918352505060028201546001600160a01b0390811660208301526003830154604083015260048301546060830152600583015460ff8082161515608085015261010091829004831660a0850152600685015460c0850152600785015460e08501526008850154918401919091526009840154610120840152600a840154610140840152600b90930154909216151561016090910152815191925016612592576001915050611356565b60006125ad82610140015183610160015184600001516141c2565b9050806125bf57600092505050611356565b600085815260126020526040812080546001600160a01b0319168155906125e9600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820180546001600160a81b031916905560068201819055600782018190556008820181905560098201819055600a820155600b01805460ff1916905561012082015161265a9085613c53565b81600001516001600160a01b03167f87abfd78e844f28318363bdf3da99eab2f4a2da9ff7ae365484507f7b6c3f80583602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001516126d08d610140015143613e1890919063ffffffff16565b6101608e01516126e1904290613e18565b60405180806020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182810382528d818151815260200191508051906020019060200280838360005b83811015612771578181015183820152602001612759565b505050509050019c5050505050505050505050505060405180910390a2600192505050600160005592915050565b6000828260405160200180836001600160a01b031660601b8152601401828152602001925050506040516020818303038152906040528051906020012090505b92915050565b600f6020526000908152604090205481565b60075481565b60045481565b61280b614280565b6001600160a01b031661281c6128af565b6001600160a01b031614612865576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6001546001600160a01b031690565b69d3c21bcecceda100000081565b600081815260106020908152604080832081516101808101835281546001600160a01b03168152600182018054845181870281018701909552808552606096959294858401939092919083018282801561294f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612931575b505050918352505060028201546001600160a01b0316602080830191909152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b9093015490921615156101409091015201519392505050565b60055481565b336000908152600e602052604090205460ff16612a365760405162461bcd60e51b81526004018080602001828103825260318152602001806155ba6031913960400191505060405180910390fd5b600c54600a54808210612a4a575050612bc1565b80841115612a56578093505b83821015612bbc576000600a8381548110612a6d57fe5b90600052602060002001549050306001600160a01b03166327b42c0f82866040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050602060405180830381600087803b158015612ad157600080fd5b505af1925050508015612af657506040513d6020811015612af157600080fd5b505160015b612b8a576040805163225fc9fd60e01b8152600481018390526001600160a01b03861660248201529051309163225fc9fd9160448083019260209291908290030181600087803b158015612b4957600080fd5b505af1925050508015612b6e57506040513d6020811015612b6957600080fd5b505160015b612b7757612b85565b80612b83575050612bbc565b505b612b98565b80612b96575050612bbc565b505b600a8381548110612ba557fe5b600091825260208220015550600190910190612a56565b50600c555b5050565b600c5481565b612bd3614280565b6001600160a01b0316612be46128af565b6001600160a01b031614612c2d576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b600a821115612c6d5760405162461bcd60e51b815260040180806020018281038252602f815260200180615350602f913960400191505060405180910390fd5b610e10811115612cae5760405162461bcd60e51b81526004018080602001828103825260288152602001806152c16028913960400191505060405180910390fd5b60088290556009819055604080518381526020810183905281517f99405003edcc25c06db454f63e8b4d88ffdb950af2cb867050c4c0c89b8ff5ec929181900390910190a15050565b606481565b7f000000000000000000000000000000000000000000000000000000000000000081565b60095481565b60026000541415612d6c576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600055600754811015612db25760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b803414612df05760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b875160011480612e01575087516002145b612e3c5760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b612e44613e75565b8515612f78577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b158015612ea357600080fd5b505afa158015612eb7573d6000803e3d6000fd5b505050506040513d6020811015612ecd57600080fd5b505188516001600160a01b0390911690631b827878908a90600090612eee57fe5b602002602001015133308a6040518563ffffffff1660e01b815260040180856001600160a01b03168152602001846001600160a01b03168152602001836001600160a01b03168152602001828152602001945050505050600060405180830381600087803b158015612f5f57600080fd5b505af1158015612f73573d6000803e3d6000fd5b505050505b6115413389898989898989896000613ef2565b600a81565b60026000541415612fd6576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b600260005560075482101561301c5760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b81341461305a5760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b89516001148061306b575089516002145b6130a65760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b8015613149577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a60018c5103815181106130e657fe5b60200260200101516001600160a01b031614613149576040805162461bcd60e51b815260206004820152601d60248201527f506f736974696f6e526f757465723a20696e76616c6964205f70617468000000604482015290519081900360640190fd5b613151613e75565b613164338b8b8b8b8b8b8b8b8b8b614718565b505060016000555050505050505050565b61025881565b610e1081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663028d27d86040518163ffffffff1660e01b815260040160206040518083038186803b1580156131da57600080fd5b505afa1580156131ee573d6000803e3d6000fd5b505050506040513d602081101561320457600080fd5b50516001600160a01b0316331461324c5760405162461bcd60e51b815260040180806020018281038252603681526020018061560e6036913960400191505060405180910390fd5b6001600160a01b038216600090815260066020526040902054806132705750612bc1565b6001600160a01b038316600081815260066020526040812055613294908383613b7e565b604080516001600160a01b0380861682528416602082015280820183905290517f4f1b51dd7a2fcb861aa2670f668be66835c4ee12b4bbbf037e4d0018f39819e49181900360600190a1505050565b600c54600a54600d54600b5490919293565b6132fd614280565b6001600160a01b031661330e6128af565b6001600160a01b031614613357576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001600160a01b03811661339c5760405162461bcd60e51b815260040180806020018281038252602681526020018061529b6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152600e602052604090205460ff166134465760405162461bcd60e51b81526004018080602001828103825260318152602001806155ba6031913960400191505060405180910390fd5b600d54600b5480821061345a575050612bc1565b80841115613466578093505b838210156135cc576000600b838154811061347d57fe5b90600052602060002001549050306001600160a01b0316630d4d003d82866040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050602060405180830381600087803b1580156134e157600080fd5b505af192505050801561350657506040513d602081101561350157600080fd5b505160015b61359a5760408051633051b17160e11b8152600481018390526001600160a01b0386166024820152905130916360a362e29160448083019260209291908290030181600087803b15801561355957600080fd5b505af192505050801561357e57506040513d602081101561357957600080fd5b505160015b61358757613595565b806135935750506135cc565b505b6135a8565b806135a65750506135cc565b505b600b83815481106135b557fe5b600091825260208220015550600190910190613466565b50600d555050565b60116020526000908152604090205481565b6010602052600090815260409020805460028201546003830154600484015460058501546006860154600787015460088801546009890154600a8a0154600b909a01546001600160a01b03998a169a999098169896979596949560ff94851695939492939192168b565b613658614280565b6001600160a01b03166136696128af565b6001600160a01b0316146136b2576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b69d3c21bcecceda10000008111156136fb5760405162461bcd60e51b815260040180806020018281038252602b8152602001806154a3602b913960400191505060405180910390fd5b60078190556040805182815290517f52a8358457e20bbb36e4086b83fb0749599f1893fe4c35a876c46dc4886d12db9181900360200190a150565b600061374d60095484614a4890919063ffffffff16565b421061378a5760405162461bcd60e51b81526004018080602001828103825260238152602001806155eb6023913960400191505060405180910390fd5b6137958484846141c2565b90505b9392505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156137fb57600080fd5b505afa15801561380f573d6000803e3d6000fd5b505050506040513d602081101561382557600080fd5b5051604080516303b6b4bb60e51b81526001600160a01b038b8116600483015288156024830152915191909216916376d69760916044808301926020929190829003018186803b15801561387857600080fd5b505afa15801561388c573d6000803e3d6000fd5b505050506040513d60208110156138a257600080fd5b5051905084156138f057828110156138eb5760405162461bcd60e51b81526004018080602001828103825260308152602001806153a36030913960400191505060405180910390fd5b61392f565b8281111561392f5760405162461bcd60e51b81526004018080602001828103825260318152602001806154726031913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b15801561398857600080fd5b505afa15801561399c573d6000803e3d6000fd5b505050506040513d60208110156139b257600080fd5b505160408051633cc8e33b60e21b81526001600160a01b038d811660048301528c811660248301528b811660448301528815156064830152608482018a905260a48201859052600060c48301819052925193169263f3238cec9260e48084019391929182900301818387803b158015613a2a57600080fd5b505af1158015613a3e573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b158015613a9d57600080fd5b505afa158015613ab1573d6000803e3d6000fd5b505050506040513d6020811015613ac757600080fd5b505160408051632662166b60e01b81526001600160a01b038e811660048301528d811660248301528c81166044830152606482018c9052608482018b905289151560a483015288811660c483015291519190921691632662166b9160e48083019260209291908290030181600087803b158015613b4357600080fd5b505af1158015613b57573d6000803e3d6000fd5b505050506040513d6020811015613b6d57600080fd5b50519b9a5050505050505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613bd0908490614aa2565b505050565b6000835160021415613c1c57613c1584600081518110613bf157fe5b602002602001015185600181518110613c0657fe5b60200260200101518585614b53565b9050613798565b60405162461bcd60e51b81526004018080602001828103825260298152602001806155086029913960400191505060405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000009050806001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613cbe57600080fd5b505af1158015613cd2573d6000803e3d6000fd5b5050600254604051600093506001600160a01b0386169250869084818181858888f193505050503d8060008114613d25576040519150601f19603f3d011682016040523d82523d6000602084013e613d2a565b606091505b505090508015613d3b575050612bc1565b816001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613d7657600080fd5b505af1158015613d8a573d6000803e3d6000fd5b5050505050816001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613de657600080fd5b505af1158015613dfa573d6000803e3d6000fd5b505050506040513d6020811015613e1057600080fd5b505050505050565b600082821115613e6f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b3415613ef0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015613ed657600080fd5b505af1158015613eea573d6000803e3d6000fd5b50505050505b565b6001600160a01b038a166000908152600f6020526040812054613f16906001614a48565b6001600160a01b03808d166000818152600f602090815260408083208690558051610180810182529384529083018f9052928d1692820192909252606081018b9052608081018a905260a0810189905287151560c082015260e0810187905261010081018690524361012082015242610140820152841515610160820152919250613fa18d8461279f565b6000818152601060209081526040909120845181546001600160a01b0319166001600160a01b0390911617815584820151805193945085939192613fed926001850192909101906151bb565b5060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160006101000a81548160ff02191690831515021790555060e082015181600701556101008201518160080155610120820151816009015561014082015181600a015561016082015181600b0160006101000a81548160ff021916908315150217905550905050600a8190806001815401808255809150506001900390600052602060002001600090919091909150558c6001600160a01b03167fa89f00a1c1cd0de066abac1a05f9314520fef2a9b98f6a99ff4548ed1161c03c8d8d8d8d8d8d8d8d8c43423a60405180806020018d6001600160a01b031681526020018c81526020018b81526020018a8152602001891515815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528e818151815260200191508051906020019060200280838360005b8381101561419557818101518382015260200161417d565b505050509050019d505050505050505050505050505060405180910390a250505050505050505050505050565b336000908152600e602052604081205460ff16156141f957436141f060085486614a4890919063ffffffff16565b11159050613798565b336001600160a01b03831614801561422557504261422260035485614a4890919063ffffffff16565b11155b614276576040805162461bcd60e51b815260206004820152601960248201527f506f736974696f6e526f757465723a20666f7262696464656e00000000000000604482015290519081900360640190fd5b5060019392505050565b3390565b600080614295888888888888614cad565b905080156143545760006142cc6127106142c66142bf600454612710613e1890919063ffffffff16565b8a90614f0b565b90614f64565b905060006142da8883613e18565b905060008960018b5103815181106142ee57fe5b602002602001015190506143308260066000846001600160a01b03166001600160a01b0316815260200190815260200160002054614a4890919063ffffffff16565b6001600160a01b039091166000908152600660205260409020555091506143599050565b859150505b9695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156143be57600080fd5b505afa1580156143d2573d6000803e3d6000fd5b505050506040513d60208110156143e857600080fd5b5051604080516303b6b4bb60e51b81526001600160a01b0388811660048301528615156024830152915191909216916376d69760916044808301926020929190829003018186803b15801561443c57600080fd5b505afa158015614450573d6000803e3d6000fd5b505050506040513d602081101561446657600080fd5b5051905082156144b457818111156144af5760405162461bcd60e51b81526004018080602001828103825260318152602001806154726031913960400191505060405180910390fd5b6144f3565b818110156144f35760405162461bcd60e51b81526004018080602001828103825260308152602001806153a36030913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b15801561454c57600080fd5b505afa158015614560573d6000803e3d6000fd5b505050506040513d602081101561457657600080fd5b505160408051633cc8e33b60e21b81526001600160a01b038a811660048301528981166024830152888116604483015286151560648301526084820188905260a48201859052600160c48301529151919092169163f3238cec9160e480830192600092919082900301818387803b1580156145f057600080fd5b505af1158015614604573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b15801561466157600080fd5b505afa158015614675573d6000803e3d6000fd5b505050506040513d602081101561468b57600080fd5b505160408051630f8ee8bb60e11b81526001600160a01b038a811660048301528981166024830152888116604483015260648201889052861515608483015291519190921691631f1dd1769160a480830192600092919082900301818387803b1580156146f757600080fd5b505af115801561470b573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038b1660009081526011602052604081205461473c906001614a48565b905080601160008e6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000604051806101a001604052808e6001600160a01b031681526020018d81526020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b03168152602001878152602001868152602001858152602001438152602001428152602001841515815250905060006147ef8e8461279f565b6000818152601260209081526040909120845181546001600160a01b0319166001600160a01b039091161781558482015180519394508593919261483b926001850192909101906151bb565b5060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a08201518160050160006101000a81548160ff02191690831515021790555060c08201518160050160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816006015561010082015181600701556101208201518160080155610140820151816009015561016082015181600a015561018082015181600b0160006101000a81548160ff021916908315150217905550905050600b8190806001815401808255809150506001900390600052602060002001600090919091909150558d6001600160a01b03167f506f2634e4508d88b04b7511af75c6d4c29b2b6f4f5067676b9400b28f3761d28e8e8e8e8e8e8e8e8e8d434260405180806020018d6001600160a01b031681526020018c81526020018b81526020018a15158152602001896001600160a01b0316815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528e818151815260200191508051906020019060200280838360005b83811015614a1a578181015183820152602001614a02565b505050509050019d505050505050505050505050505060405180910390a25050505050505050505050505050565b600082820183811015613798576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000614af7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614fcb9092919063ffffffff16565b805190915015613bd057808060200190516020811015614b1657600080fd5b5051613bd05760405162461bcd60e51b815260040180806020018281038252602a815260200180615590602a913960400191505060405180910390fd5b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015614baf57600080fd5b505afa158015614bc3573d6000803e3d6000fd5b505050506040513d6020811015614bd957600080fd5b505160408051634998b10960e11b81526001600160a01b038981166004830152888116602483015286811660448301529151919092169163933162129160648083019260209291908290030181600087803b158015614c3757600080fd5b505af1158015614c4b573d6000803e3d6000fd5b505050506040513d6020811015614c6157600080fd5b5051905083811015614ca45760405162461bcd60e51b815260040180806020018281038252602b8152602001806152e9602b913960400191505060405180910390fd5b95945050505050565b600082614cbc57506000614359565b81614cc957506001614359565b600086600188510381518110614cdb57fe5b6020026020010151905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015614d4057600080fd5b505afa158015614d54573d6000803e3d6000fd5b505050506040513d6020811015614d6a57600080fd5b505160408051634a3f088d60e01b81526001600160a01b038c8116600483015285811660248301528981166044830152881515606483015291519293506000928392851691634a3f088d91608480830192610100929190829003018186803b158015614dd557600080fd5b505afa158015614de9573d6000803e3d6000fd5b505050506040513d610100811015614e0057600080fd5b508051602090910151909250905081614e20576000945050505050614359565b6000614e2c8388614a48565b90506000846001600160a01b0316630a48d5a9878d6040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b158015614e8557600080fd5b505afa158015614e99573d6000803e3d6000fd5b505050506040513d6020811015614eaf57600080fd5b505190506000614ebf8483614a48565b90506000614ed3856142c688612710614f0b565b90506000614ef4836142c66005546127100188614f0b90919063ffffffff16565b919091109f9e505050505050505050505050505050565b600082614f1a575060006127df565b82820282848281614f2757fe5b04146137985760405162461bcd60e51b81526004018080602001828103825260218152602001806154316021913960400191505060405180910390fd5b6000808211614fba576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381614fc357fe5b049392505050565b6060613795848460008585614fdf856150f0565b615030576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b6020831061506e5780518252601f19909201916020918201910161504f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146150d0576040519150601f19603f3d011682016040523d82523d6000602084013e6150d5565b606091505b50915091506150e58282866150f6565b979650505050505050565b3b151590565b60608315615105575081613798565b8251156151155782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561515f578181015183820152602001615147565b50505050905090810190601f16801561518c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50805460008255906000526020600020908101906151b89190615220565b50565b828054828255906000526020600020908101928215615210579160200282015b8281111561521057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906151db565b5061521c929150615220565b5090565b5b8082111561521c576000815560010161522156fe506f736974696f6e526f757465723a20696e76616c696420657865637574696f6e4665655265656e7472616e637947756172643a207265656e7472616e742063616c6c00506f736974696f6e526f757465723a20696e76616c6964206d73672e76616c75654f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373506f736974696f6e526f757465723a206d617854696d6544656c617920697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e73756666696369656e7420616d6f756e744f7574506f736974696f6e526f757465723a20696e637265617365506f736974696f6e526571756573744b657973537461727420697320746f6f2068696768506f736974696f6e526f757465723a206d696e426c6f636b44656c61794b656570657220697320746f6f2068696768506f736974696f6e526f757465723a20696e76616c6964205f70617468206c656e67746842617365506f736974696f6e4d616e616765723a206d61726b207072696365206c6f776572207468616e206c696d697442617365506f736974696f6e4d616e616765723a206465706f73697446656520697320746f6f206869676842617365506f736974696f6e4d616e616765723a206d696e54696d6544656c61795075626c696320697320746f6f2068696768536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657242617365506f736974696f6e4d616e616765723a206d61726b20707269636520686967686572207468616e206c696d6974506f736974696f6e526f757465723a206d696e457865637574696f6e46656520697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e637265617365506f736974696f6e42756666657242707320697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e76616c6964205f706174682e6c656e677468506f736974696f6e526f757465723a206465637265617365506f736974696f6e526571756573744b657973537461727420697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e76616c69642073656e6465725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564506f736974696f6e526f757465723a2063616c6c6572206973206e6f742074686520706f736974696f6e206b6565706572506f736974696f6e526f757465723a207265717565737420686173206578706972656442617365506f736974696f6e4d616e616765723a204f6e6c792050686c704d616e616765722063616e20776974686472617720666565a2646970667358221220db5c7d6bcf347f36e6f5c8a74b98d7af148e702fa0b3c420a62461ba89809bd364736f6c6343000706003342617365506f736974696f6e4d616e616765723a2077657468206973207a65726f206164647265737342617365506f736974696f6e4d616e616765723a2061646472657373657350726f7669646572206973207a65726f206164647265737342617365506f736974696f6e4d616e616765723a206465706f73697446656520697320746f6f2068696768506f736974696f6e526f757465723a206d696e457865637574696f6e46656520697320746f6f20686967680000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f1000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000a2a15d09519be00000

Deployed ByteCode

0x6080604052600436106102e85760003560e01c8063633451de11610190578063cb0269c9116100dc578063f255527811610095578063f3883d8b1161006f578063f3883d8b14610d2c578063fa44457714610d65578063faf990f314610d98578063fc2cee6214610e2657610356565b8063f255527814610c83578063f2cea6a514610cbe578063f2fde38b14610cf957610356565b8063cb0269c914610a79578063ceed2cc114610a8e578063d467a4ae14610b60578063e70dd2fc14610b75578063e8caee1c14610c59578063ec2a1bf214610c6e57610356565b806395e9bbd7116101495780639b578620116101235780639b57862014610a0a578063a4e7684f14610a1f578063c6d87dd514610a4f578063c72c4d1014610a6457610356565b806395e9bbd71461099257806398d1e03a146109bc5780639a208100146109d157610356565b8063633451de146108f657806363ae21031461092957806367a527931461093e578063715018a6146109535780638da5cb5b146109685780638f6494941461097d57610356565b80632d79cf421161024f5780633fc8cef3116102085780635841fcaa116101e25780635841fcaa146107f55780635d5c22e81461080a57806360a362e21461088457806362f8a3fe146108bd57610356565b80633fc8cef3146107705780634278555f146107a1578063490ae210146107cb57610356565b80632d79cf421461067e578063308aa81f146106935780633422ead1146106c357806336eba48a146106fe5780633a2a80c7146107315780633a9b52ad1461074657610356565b80631ce9cb8f116102a15780631ce9cb8f146104d95780631f2851061461050c578063225fc9fd146105b8578063233bfe3b146105f157806327b42c0f1461061b5780632b73fb181461065457610356565b8063042259541461035b5780630d4d003d14610397578063126082cf146103e4578063133e5b17146103f957806315de6386146103e45780631bca8cf0146104c457610356565b3661035657336001600160a01b037f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2716146103545760405162461bcd60e51b815260040180806020018281038252602381526020018061556d6023913960400191505060405180910390fd5b005b600080fd5b34801561036757600080fd5b506103856004803603602081101561037e57600080fd5b5035610e50565b60408051918252519081900360200190f35b3480156103a357600080fd5b506103d0600480360360408110156103ba57600080fd5b50803590602001356001600160a01b0316610e71565b604080519115158252519081900360200190f35b3480156103f057600080fd5b50610385611361565b610354600480360360e081101561040f57600080fd5b81019060208101813564010000000081111561042a57600080fd5b82018360208201111561043c57600080fd5b8035906020019184602083028401116401000000008311171561045e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b0383351693505050602081013590604081013590606081013515159060808101359060a00135611367565b3480156104d057600080fd5b50610385611550565b3480156104e557600080fd5b50610385600480360360208110156104fc57600080fd5b50356001600160a01b0316611556565b34801561051857600080fd5b506105366004803603602081101561052f57600080fd5b5035611568565b604051808d6001600160a01b031681526020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182151581526020019c5050505050505050505050505060405180910390f35b3480156105c457600080fd5b506103d0600480360360408110156105db57600080fd5b50803590602001356001600160a01b03166115d4565b3480156105fd57600080fd5b506103546004803603602081101561061457600080fd5b5035611974565b34801561062757600080fd5b506103d06004803603604081101561063e57600080fd5b50803590602001356001600160a01b0316611a52565b34801561066057600080fd5b506103546004803603602081101561067757600080fd5b5035611e53565b34801561068a57600080fd5b50610385611f31565b34801561069f57600080fd5b50610354600480360360408110156106b657600080fd5b5080359060200135611f37565b3480156106cf57600080fd5b50610354600480360360408110156106e657600080fd5b506001600160a01b0381351690602001351515612064565b34801561070a57600080fd5b506103d06004803603602081101561072157600080fd5b50356001600160a01b0316612126565b34801561073d57600080fd5b5061038561213b565b34801561075257600080fd5b506103546004803603602081101561076957600080fd5b5035612141565b34801561077c57600080fd5b506107856121de565b604080516001600160a01b039092168252519081900360200190f35b3480156107ad57600080fd5b50610385600480360360208110156107c457600080fd5b5035612202565b3480156107d757600080fd5b50610354600480360360208110156107ee57600080fd5b5035612212565b34801561080157600080fd5b506103856122ef565b34801561081657600080fd5b506108346004803603602081101561082d57600080fd5b50356122f5565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610870578181015183820152602001610858565b505050509050019250505060405180910390f35b34801561089057600080fd5b506103d0600480360360408110156108a757600080fd5b50803590602001356001600160a01b0316612419565b3480156108c957600080fd5b50610385600480360360408110156108e057600080fd5b506001600160a01b03813516906020013561279f565b34801561090257600080fd5b506103856004803603602081101561091957600080fd5b50356001600160a01b03166127e5565b34801561093557600080fd5b506103856127f7565b34801561094a57600080fd5b506103856127fd565b34801561095f57600080fd5b50610354612803565b34801561097457600080fd5b506107856128af565b34801561098957600080fd5b506103856128be565b34801561099e57600080fd5b50610834600480360360208110156109b557600080fd5b50356128cc565b3480156109c857600080fd5b506103856129e2565b3480156109dd57600080fd5b50610354600480360360408110156109f457600080fd5b50803590602001356001600160a01b03166129e8565b348015610a1657600080fd5b50610385612bc5565b348015610a2b57600080fd5b5061035460048036036040811015610a4257600080fd5b5080359060200135612bcb565b348015610a5b57600080fd5b50610385612cf7565b348015610a7057600080fd5b50610785612cfc565b348015610a8557600080fd5b50610385612d20565b6103546004803603610100811015610aa557600080fd5b810190602081018135640100000000811115610ac057600080fd5b820183602082011115610ad257600080fd5b80359060200191846020830284011164010000000083111715610af457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550506001600160a01b0383351693505050602081013590604081013590606081013590608081013515159060a08101359060c00135612d26565b348015610b6c57600080fd5b50610385612f8b565b6103546004803603610140811015610b8c57600080fd5b810190602081018135640100000000811115610ba757600080fd5b820183602082011115610bb957600080fd5b80359060200191846020830284011164010000000083111715610bdb57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505081356001600160a01b0390811693506020830135926040810135925060608101351515916080820135169060a08101359060c08101359060e08101359061010001351515612f90565b348015610c6557600080fd5b50610385613175565b348015610c7a57600080fd5b5061038561317b565b348015610c8f57600080fd5b5061035460048036036040811015610ca657600080fd5b506001600160a01b0381358116916020013516613181565b348015610cca57600080fd5b50610cd36132e3565b604080519485526020850193909352838301919091526060830152519081900360800190f35b348015610d0557600080fd5b5061035460048036036020811015610d1c57600080fd5b50356001600160a01b03166132f5565b348015610d3857600080fd5b5061035460048036036040811015610d4f57600080fd5b50803590602001356001600160a01b03166133f8565b348015610d7157600080fd5b5061038560048036036020811015610d8857600080fd5b50356001600160a01b03166135d4565b348015610da457600080fd5b50610dc260048036036020811015610dbb57600080fd5b50356135e6565b604080516001600160a01b039c8d1681529a909b1660208b0152898b01989098526060890196909652608088019490945291151560a087015260c086015260e085015261010084015261012083015215156101408201529051908190036101600190f35b348015610e3257600080fd5b5061035460048036036020811015610e4957600080fd5b5035613650565b600a8181548110610e6057600080fd5b600091825260209091200154905081565b600060026000541415610eb9576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260126020908152604080832081516101a08101835281546001600160a01b031681526001820180548451818702810187019095528085529194929385840193909290830182828015610f3e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f20575b505050918352505060028201546001600160a01b0390811660208301526003830154604083015260048301546060830152600583015460ff8082161515608085015261010091829004831660a0850152600685015460c0850152600785015460e08501526008850154918401919091526009840154610120840152600a840154610140840152600b90930154909216151561016090910152815191925016610fea576001915050611356565b60006110058261014001518361016001518460000151613736565b90508061101757600092505050611356565b600085815260126020526040812080546001600160a01b031916815590611041600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820180546001600160a81b031916905560068201819055600782018190556008820181905560098201819055600a8201819055600b909101805460ff191690558251602084015180516110e492919084906110bd57fe5b60200260200101518560400151866060015187608001518860a00151308a60e0015161379f565b9050801561120b57600183602001515111156111cc576111b57f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d602081101561118057600080fd5b50516020850151805184919060009061119557fe5b60200260200101516001600160a01b0316613b7e9092919063ffffffff16565b6111c9836020015184610100015130613bd5565b90505b826101800151156111ea576111e5818460c00151613c53565b61120b565b61120b8360c001518285602001516001876020015151038151811061119557fe5b61121a83610120015186613c53565b82600001516001600160a01b03167f21435c5b618d77ff3657140cd3318e2cffaebc5e0e1b7318f56a9ba4044c3ed284602001518560400151866060015187608001518860a001518960c001518a60e001518b61010001518c61012001516112908e610140015143613e1890919063ffffffff16565b6101608f01516112a1904290613e18565b60405180806020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182810382528d818151815260200191508051906020019060200280838360005b83811015611331578181015183820152602001611319565b505050509050019c5050505050505050505050505060405180910390a2600193505050505b600160005592915050565b61271081565b600260005414156113ad576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b60026000556007548110156113f35760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b803410156114325760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b865160011480611443575086516002145b61147e5760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a276001600160a01b0316876000815181106114b557fe5b60200260200101516001600160a01b031614611518576040805162461bcd60e51b815260206004820152601d60248201527f506f736974696f6e526f757465723a20696e76616c6964205f70617468000000604482015290519081900360640190fd5b611520613e75565b600061152c3483613e18565b9050611541338989848a8a8a8a8a6001613ef2565b50506001600055505050505050565b600d5481565b60066020526000908152604090205481565b6012602052600090815260409020805460028201546003830154600484015460058501546006860154600787015460088801546009890154600a8a0154600b909a01546001600160a01b03998a169a988a16999798969760ff808816986101009098049091169691168c565b60006002600054141561161c576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260106020908152604080832081516101808101835281546001600160a01b0316815260018201805484518187028101870190955280855291949293858401939092908301828280156116a157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611683575b505050918352505060028201546001600160a01b039081166020830152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b9093015490921615156101409091015281519192501661173d576001915050611356565b600061175882610120015183610140015184600001516141c2565b90508061176a57600092505050611356565b600085815260106020526040812080546001600160a01b031916815590611794600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560068201805460ff19908116909155600783018290556008830182905560098301829055600a830191909155600b90910180549091169055610160820151156118185761181382606001518360000151613c53565b611836565b61183682600001518360600151846020015160008151811061119557fe5b61184582610100015185613c53565b81600001516001600160a01b03167f35b638e650e2328786fb405bd69d2083dbedc018d086662e74b775b4f1dae4bf83602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516118b58c610120015143613e1890919063ffffffff16565b6101408d01516118c6904290613e18565b60405180806020018b6001600160a01b031681526020018a8152602001898152602001888152602001871515815260200186815260200185815260200184815260200183815260200182810382528c818151815260200191508051906020019060200280838360005b8381101561194757818101518382015260200161192f565b505050509050019b50505050505050505050505060405180910390a2600192505050600160005592915050565b61197c614280565b6001600160a01b031661198d6128af565b6001600160a01b0316146119d6576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b612710811115611a175760405162461bcd60e51b815260040180806020018281038252603a8152602001806154ce603a913960400191505060405180910390fd5b60058190556040805182815290517f21167d0d4661af93817ebce920f18986eed3d75d5e1c03f2aed05efcbafbc4529181900360200190a150565b600060026000541415611a9a576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260106020908152604080832081516101808101835281546001600160a01b031681526001820180548451818702810187019095528085529194929385840193909290830182828015611b1f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611b01575b505050918352505060028201546001600160a01b039081166020830152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b90930154909216151561014090910152815191925016611bbb576001915050611356565b6000611bd68261012001518361014001518460000151613736565b905080611be857600092505050611356565b600085815260106020526040812080546001600160a01b031916815590611c12600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560068201805460ff19908116909155600783018290556008830182905560098301829055600a830191909155600b90910180549091169055606082015115611d965760008260600151905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015611ce257600080fd5b505afa158015611cf6573d6000803e3d6000fd5b505050506040513d6020811015611d0c57600080fd5b505160208501515190915060011015611d4f57611d39818560600151866020015160008151811061119557fe5b611d4c8460200151856080015130613bd5565b91505b6000611d73856000015186602001518588604001518960c001518a60a00151614284565b9050611d92828287602001516001896020015151038151811061119557fe5b5050505b815160208301518051611dd49291906000198101908110611db357fe5b602002602001015184604001518560a001518660c001518760e00151614363565b611de382610100015185613c53565b81600001516001600160a01b03167f1be316b94d38c07bd41cdb4913772d0a0a82802786a2f8b657b6e85dbcdfc64183602001518460400151856060015186608001518760a001518860c001518960e001518a61010001516118b58c610120015143613e1890919063ffffffff16565b611e5b614280565b6001600160a01b0316611e6c6128af565b6001600160a01b031614611eb5576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b610258811115611ef65760405162461bcd60e51b81526004018080602001828103825260338152602001806153fe6033913960400191505060405180910390fd5b60038190556040805182815290517fbd7411e312e9c7c95b6798503250129c3b613975a11dc36e76f469c5b8e8bcd59181900360200190a150565b60025481565b611f3f614280565b6001600160a01b0316611f506128af565b6001600160a01b031614611f99576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b600a54821115611fda5760405162461bcd60e51b815260040180806020018281038252603c815260200180615314603c913960400191505060405180910390fd5b600b5481111561201b5760405162461bcd60e51b815260040180806020018281038252603c815260200180615531603c913960400191505060405180910390fd5b600c829055600d819055604080518381526020810183905281517febb0f666150f4be5b60c45df8f3e49992510b0128027fe58eea6110f296493bc929181900390910190a15050565b61206c614280565b6001600160a01b031661207d6128af565b6001600160a01b0316146120c6576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001600160a01b0382166000818152600e6020908152604091829020805460ff1916851515908117909155825190815291517ffbabc02389290a451c6e600d05bf9887b99bfad39d8e1237e4e3df042e4941fe9281900390910190a25050565b600e6020526000908152604090205460ff1681565b60035481565b612149614280565b6001600160a01b031661215a6128af565b6001600160a01b0316146121a3576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b60028190556040805182815290517f4d371d598d3a13f99ce992a17975bbaf1e1c256e072ec7d2f93ce88e40d9ba1c9181900360200190a150565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b600b8181548110610e6057600080fd5b61221a614280565b6001600160a01b031661222b6128af565b6001600160a01b031614612274576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b60648111156122b45760405162461bcd60e51b815260040180806020018281038252602b8152602001806153d3602b913960400191505060405180910390fd5b60048190556040805182815290517f974fd3c1fcb4653dfc4fb740c4c692cd212d55c28f163f310128cb64d83006759181900360200190a150565b60085481565b600081815260126020908152604080832081516101a08101835281546001600160a01b03168152600182018054845181870281018701909552808552606096959294858401939092919083018282801561237857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161235a575b505050918352505060028201546001600160a01b039081166020808401919091526003840154604084015260048401546060840152600584015460ff808216151560808601526101009182900490931660a0850152600685015460c0850152600785015460e08501526008850154908401526009840154610120840152600a840154610140840152600b909301541615156101609091015201519392505050565b600060026000541415612461576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600090815583815260126020908152604080832081516101a08101835281546001600160a01b0316815260018201805484518187028101870190955280855291949293858401939092908301828280156124e657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116124c8575b505050918352505060028201546001600160a01b0390811660208301526003830154604083015260048301546060830152600583015460ff8082161515608085015261010091829004831660a0850152600685015460c0850152600785015460e08501526008850154918401919091526009840154610120840152600a840154610140840152600b90930154909216151561016090910152815191925016612592576001915050611356565b60006125ad82610140015183610160015184600001516141c2565b9050806125bf57600092505050611356565b600085815260126020526040812080546001600160a01b0319168155906125e9600183018261519a565b506002810180546001600160a01b0319169055600060038201819055600482018190556005820180546001600160a81b031916905560068201819055600782018190556008820181905560098201819055600a820155600b01805460ff1916905561012082015161265a9085613c53565b81600001516001600160a01b03167f87abfd78e844f28318363bdf3da99eab2f4a2da9ff7ae365484507f7b6c3f80583602001518460400151856060015186608001518760a001518860c001518960e001518a61010001518b61012001516126d08d610140015143613e1890919063ffffffff16565b6101608e01516126e1904290613e18565b60405180806020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b0316815260200187815260200186815260200185815260200184815260200183815260200182810382528d818151815260200191508051906020019060200280838360005b83811015612771578181015183820152602001612759565b505050509050019c5050505050505050505050505060405180910390a2600192505050600160005592915050565b6000828260405160200180836001600160a01b031660601b8152601401828152602001925050506040516020818303038152906040528051906020012090505b92915050565b600f6020526000908152604090205481565b60075481565b60045481565b61280b614280565b6001600160a01b031661281c6128af565b6001600160a01b031614612865576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6001546001600160a01b031690565b69d3c21bcecceda100000081565b600081815260106020908152604080832081516101808101835281546001600160a01b03168152600182018054845181870281018701909552808552606096959294858401939092919083018282801561294f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612931575b505050918352505060028201546001600160a01b0316602080830191909152600383015460408301526004830154606083015260058301546080830152600683015460ff908116151560a0840152600784015460c0840152600884015460e08401526009840154610100840152600a840154610120840152600b9093015490921615156101409091015201519392505050565b60055481565b336000908152600e602052604090205460ff16612a365760405162461bcd60e51b81526004018080602001828103825260318152602001806155ba6031913960400191505060405180910390fd5b600c54600a54808210612a4a575050612bc1565b80841115612a56578093505b83821015612bbc576000600a8381548110612a6d57fe5b90600052602060002001549050306001600160a01b03166327b42c0f82866040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050602060405180830381600087803b158015612ad157600080fd5b505af1925050508015612af657506040513d6020811015612af157600080fd5b505160015b612b8a576040805163225fc9fd60e01b8152600481018390526001600160a01b03861660248201529051309163225fc9fd9160448083019260209291908290030181600087803b158015612b4957600080fd5b505af1925050508015612b6e57506040513d6020811015612b6957600080fd5b505160015b612b7757612b85565b80612b83575050612bbc565b505b612b98565b80612b96575050612bbc565b505b600a8381548110612ba557fe5b600091825260208220015550600190910190612a56565b50600c555b5050565b600c5481565b612bd3614280565b6001600160a01b0316612be46128af565b6001600160a01b031614612c2d576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b600a821115612c6d5760405162461bcd60e51b815260040180806020018281038252602f815260200180615350602f913960400191505060405180910390fd5b610e10811115612cae5760405162461bcd60e51b81526004018080602001828103825260288152602001806152c16028913960400191505060405180910390fd5b60088290556009819055604080518381526020810183905281517f99405003edcc25c06db454f63e8b4d88ffdb950af2cb867050c4c0c89b8ff5ec929181900390910190a15050565b606481565b7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f181565b60095481565b60026000541415612d6c576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b6002600055600754811015612db25760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b803414612df05760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b875160011480612e01575087516002145b612e3c5760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b612e44613e75565b8515612f78577f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b158015612ea357600080fd5b505afa158015612eb7573d6000803e3d6000fd5b505050506040513d6020811015612ecd57600080fd5b505188516001600160a01b0390911690631b827878908a90600090612eee57fe5b602002602001015133308a6040518563ffffffff1660e01b815260040180856001600160a01b03168152602001846001600160a01b03168152602001836001600160a01b03168152602001828152602001945050505050600060405180830381600087803b158015612f5f57600080fd5b505af1158015612f73573d6000803e3d6000fd5b505050505b6115413389898989898989896000613ef2565b600a81565b60026000541415612fd6576040805162461bcd60e51b815260206004820152601f602482015260008051602061525a833981519152604482015290519081900360640190fd5b600260005560075482101561301c5760405162461bcd60e51b81526004018080602001828103825260248152602001806152366024913960400191505060405180910390fd5b81341461305a5760405162461bcd60e51b815260040180806020018281038252602181526020018061527a6021913960400191505060405180910390fd5b89516001148061306b575089516002145b6130a65760405162461bcd60e51b815260040180806020018281038252602481526020018061537f6024913960400191505060405180910390fd5b8015613149577f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a276001600160a01b03168a60018c5103815181106130e657fe5b60200260200101516001600160a01b031614613149576040805162461bcd60e51b815260206004820152601d60248201527f506f736974696f6e526f757465723a20696e76616c6964205f70617468000000604482015290519081900360640190fd5b613151613e75565b613164338b8b8b8b8b8b8b8b8b8b614718565b505060016000555050505050505050565b61025881565b610e1081565b7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663028d27d86040518163ffffffff1660e01b815260040160206040518083038186803b1580156131da57600080fd5b505afa1580156131ee573d6000803e3d6000fd5b505050506040513d602081101561320457600080fd5b50516001600160a01b0316331461324c5760405162461bcd60e51b815260040180806020018281038252603681526020018061560e6036913960400191505060405180910390fd5b6001600160a01b038216600090815260066020526040902054806132705750612bc1565b6001600160a01b038316600081815260066020526040812055613294908383613b7e565b604080516001600160a01b0380861682528416602082015280820183905290517f4f1b51dd7a2fcb861aa2670f668be66835c4ee12b4bbbf037e4d0018f39819e49181900360600190a1505050565b600c54600a54600d54600b5490919293565b6132fd614280565b6001600160a01b031661330e6128af565b6001600160a01b031614613357576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b6001600160a01b03811661339c5760405162461bcd60e51b815260040180806020018281038252602681526020018061529b6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b336000908152600e602052604090205460ff166134465760405162461bcd60e51b81526004018080602001828103825260318152602001806155ba6031913960400191505060405180910390fd5b600d54600b5480821061345a575050612bc1565b80841115613466578093505b838210156135cc576000600b838154811061347d57fe5b90600052602060002001549050306001600160a01b0316630d4d003d82866040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050602060405180830381600087803b1580156134e157600080fd5b505af192505050801561350657506040513d602081101561350157600080fd5b505160015b61359a5760408051633051b17160e11b8152600481018390526001600160a01b0386166024820152905130916360a362e29160448083019260209291908290030181600087803b15801561355957600080fd5b505af192505050801561357e57506040513d602081101561357957600080fd5b505160015b61358757613595565b806135935750506135cc565b505b6135a8565b806135a65750506135cc565b505b600b83815481106135b557fe5b600091825260208220015550600190910190613466565b50600d555050565b60116020526000908152604090205481565b6010602052600090815260409020805460028201546003830154600484015460058501546006860154600787015460088801546009890154600a8a0154600b909a01546001600160a01b03998a169a999098169896979596949560ff94851695939492939192168b565b613658614280565b6001600160a01b03166136696128af565b6001600160a01b0316146136b2576040805162461bcd60e51b81526020600482018190526024820152600080516020615452833981519152604482015290519081900360640190fd5b69d3c21bcecceda10000008111156136fb5760405162461bcd60e51b815260040180806020018281038252602b8152602001806154a3602b913960400191505060405180910390fd5b60078190556040805182815290517f52a8358457e20bbb36e4086b83fb0749599f1893fe4c35a876c46dc4886d12db9181900360200190a150565b600061374d60095484614a4890919063ffffffff16565b421061378a5760405162461bcd60e51b81526004018080602001828103825260238152602001806155eb6023913960400191505060405180910390fd5b6137958484846141c2565b90505b9392505050565b6000807f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156137fb57600080fd5b505afa15801561380f573d6000803e3d6000fd5b505050506040513d602081101561382557600080fd5b5051604080516303b6b4bb60e51b81526001600160a01b038b8116600483015288156024830152915191909216916376d69760916044808301926020929190829003018186803b15801561387857600080fd5b505afa15801561388c573d6000803e3d6000fd5b505050506040513d60208110156138a257600080fd5b5051905084156138f057828110156138eb5760405162461bcd60e51b81526004018080602001828103825260308152602001806153a36030913960400191505060405180910390fd5b61392f565b8281111561392f5760405162461bcd60e51b81526004018080602001828103825260318152602001806154726031913960400191505060405180910390fd5b7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b15801561398857600080fd5b505afa15801561399c573d6000803e3d6000fd5b505050506040513d60208110156139b257600080fd5b505160408051633cc8e33b60e21b81526001600160a01b038d811660048301528c811660248301528b811660448301528815156064830152608482018a905260a48201859052600060c48301819052925193169263f3238cec9260e48084019391929182900301818387803b158015613a2a57600080fd5b505af1158015613a3e573d6000803e3d6000fd5b5050505060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b158015613a9d57600080fd5b505afa158015613ab1573d6000803e3d6000fd5b505050506040513d6020811015613ac757600080fd5b505160408051632662166b60e01b81526001600160a01b038e811660048301528d811660248301528c81166044830152606482018c9052608482018b905289151560a483015288811660c483015291519190921691632662166b9160e48083019260209291908290030181600087803b158015613b4357600080fd5b505af1158015613b57573d6000803e3d6000fd5b505050506040513d6020811015613b6d57600080fd5b50519b9a5050505050505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613bd0908490614aa2565b505050565b6000835160021415613c1c57613c1584600081518110613bf157fe5b602002602001015185600181518110613c0657fe5b60200260200101518585614b53565b9050613798565b60405162461bcd60e51b81526004018080602001828103825260298152602001806155086029913960400191505060405180910390fd5b60007f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a279050806001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015613cbe57600080fd5b505af1158015613cd2573d6000803e3d6000fd5b5050600254604051600093506001600160a01b0386169250869084818181858888f193505050503d8060008114613d25576040519150601f19603f3d011682016040523d82523d6000602084013e613d2a565b606091505b505090508015613d3b575050612bc1565b816001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613d7657600080fd5b505af1158015613d8a573d6000803e3d6000fd5b5050505050816001600160a01b031663a9059cbb84866040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613de657600080fd5b505af1158015613dfa573d6000803e3d6000fd5b505050506040513d6020811015613e1057600080fd5b505050505050565b600082821115613e6f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b3415613ef0577f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a276001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015613ed657600080fd5b505af1158015613eea573d6000803e3d6000fd5b50505050505b565b6001600160a01b038a166000908152600f6020526040812054613f16906001614a48565b6001600160a01b03808d166000818152600f602090815260408083208690558051610180810182529384529083018f9052928d1692820192909252606081018b9052608081018a905260a0810189905287151560c082015260e0810187905261010081018690524361012082015242610140820152841515610160820152919250613fa18d8461279f565b6000818152601060209081526040909120845181546001600160a01b0319166001600160a01b0390911617815584820151805193945085939192613fed926001850192909101906151bb565b5060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160006101000a81548160ff02191690831515021790555060e082015181600701556101008201518160080155610120820151816009015561014082015181600a015561016082015181600b0160006101000a81548160ff021916908315150217905550905050600a8190806001815401808255809150506001900390600052602060002001600090919091909150558c6001600160a01b03167fa89f00a1c1cd0de066abac1a05f9314520fef2a9b98f6a99ff4548ed1161c03c8d8d8d8d8d8d8d8d8c43423a60405180806020018d6001600160a01b031681526020018c81526020018b81526020018a8152602001891515815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528e818151815260200191508051906020019060200280838360005b8381101561419557818101518382015260200161417d565b505050509050019d505050505050505050505050505060405180910390a250505050505050505050505050565b336000908152600e602052604081205460ff16156141f957436141f060085486614a4890919063ffffffff16565b11159050613798565b336001600160a01b03831614801561422557504261422260035485614a4890919063ffffffff16565b11155b614276576040805162461bcd60e51b815260206004820152601960248201527f506f736974696f6e526f757465723a20666f7262696464656e00000000000000604482015290519081900360640190fd5b5060019392505050565b3390565b600080614295888888888888614cad565b905080156143545760006142cc6127106142c66142bf600454612710613e1890919063ffffffff16565b8a90614f0b565b90614f64565b905060006142da8883613e18565b905060008960018b5103815181106142ee57fe5b602002602001015190506143308260066000846001600160a01b03166001600160a01b0316815260200190815260200160002054614a4890919063ffffffff16565b6001600160a01b039091166000908152600660205260409020555091506143599050565b859150505b9695505050505050565b60007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b1580156143be57600080fd5b505afa1580156143d2573d6000803e3d6000fd5b505050506040513d60208110156143e857600080fd5b5051604080516303b6b4bb60e51b81526001600160a01b0388811660048301528615156024830152915191909216916376d69760916044808301926020929190829003018186803b15801561443c57600080fd5b505afa158015614450573d6000803e3d6000fd5b505050506040513d602081101561446657600080fd5b5051905082156144b457818111156144af5760405162461bcd60e51b81526004018080602001828103825260318152602001806154726031913960400191505060405180910390fd5b6144f3565b818110156144f35760405162461bcd60e51b81526004018080602001828103825260308152602001806153a36030913960400191505060405180910390fd5b7f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316630af785596040518163ffffffff1660e01b815260040160206040518083038186803b15801561454c57600080fd5b505afa158015614560573d6000803e3d6000fd5b505050506040513d602081101561457657600080fd5b505160408051633cc8e33b60e21b81526001600160a01b038a811660048301528981166024830152888116604483015286151560648301526084820188905260a48201859052600160c48301529151919092169163f3238cec9160e480830192600092919082900301818387803b1580156145f057600080fd5b505af1158015614604573d6000803e3d6000fd5b505050507f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b031663b0f479a16040518163ffffffff1660e01b815260040160206040518083038186803b15801561466157600080fd5b505afa158015614675573d6000803e3d6000fd5b505050506040513d602081101561468b57600080fd5b505160408051630f8ee8bb60e11b81526001600160a01b038a811660048301528981166024830152888116604483015260648201889052861515608483015291519190921691631f1dd1769160a480830192600092919082900301818387803b1580156146f757600080fd5b505af115801561470b573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038b1660009081526011602052604081205461473c906001614a48565b905080601160008e6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000604051806101a001604052808e6001600160a01b031681526020018d81526020018c6001600160a01b031681526020018b81526020018a81526020018915158152602001886001600160a01b03168152602001878152602001868152602001858152602001438152602001428152602001841515815250905060006147ef8e8461279f565b6000818152601260209081526040909120845181546001600160a01b0319166001600160a01b039091161781558482015180519394508593919261483b926001850192909101906151bb565b5060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a08201518160050160006101000a81548160ff02191690831515021790555060c08201518160050160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816006015561010082015181600701556101208201518160080155610140820151816009015561016082015181600a015561018082015181600b0160006101000a81548160ff021916908315150217905550905050600b8190806001815401808255809150506001900390600052602060002001600090919091909150558d6001600160a01b03167f506f2634e4508d88b04b7511af75c6d4c29b2b6f4f5067676b9400b28f3761d28e8e8e8e8e8e8e8e8e8d434260405180806020018d6001600160a01b031681526020018c81526020018b81526020018a15158152602001896001600160a01b0316815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528e818151815260200191508051906020019060200280838360005b83811015614a1a578181015183820152602001614a02565b505050509050019d505050505050505050505050505060405180910390a25050505050505050505050505050565b600082820183811015613798576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000614af7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614fcb9092919063ffffffff16565b805190915015613bd057808060200190516020811015614b1657600080fd5b5051613bd05760405162461bcd60e51b815260040180806020018281038252602a815260200180615590602a913960400191505060405180910390fd5b6000807f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015614baf57600080fd5b505afa158015614bc3573d6000803e3d6000fd5b505050506040513d6020811015614bd957600080fd5b505160408051634998b10960e11b81526001600160a01b038981166004830152888116602483015286811660448301529151919092169163933162129160648083019260209291908290030181600087803b158015614c3757600080fd5b505af1158015614c4b573d6000803e3d6000fd5b505050506040513d6020811015614c6157600080fd5b5051905083811015614ca45760405162461bcd60e51b815260040180806020018281038252602b8152602001806152e9602b913960400191505060405180910390fd5b95945050505050565b600082614cbc57506000614359565b81614cc957506001614359565b600086600188510381518110614cdb57fe5b6020026020010151905060007f0000000000000000000000003cf8f33789ab2c9ec6a8f6fd5f074f4a8a0547f16001600160a01b0316638d928af86040518163ffffffff1660e01b815260040160206040518083038186803b158015614d4057600080fd5b505afa158015614d54573d6000803e3d6000fd5b505050506040513d6020811015614d6a57600080fd5b505160408051634a3f088d60e01b81526001600160a01b038c8116600483015285811660248301528981166044830152881515606483015291519293506000928392851691634a3f088d91608480830192610100929190829003018186803b158015614dd557600080fd5b505afa158015614de9573d6000803e3d6000fd5b505050506040513d610100811015614e0057600080fd5b508051602090910151909250905081614e20576000945050505050614359565b6000614e2c8388614a48565b90506000846001600160a01b0316630a48d5a9878d6040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b158015614e8557600080fd5b505afa158015614e99573d6000803e3d6000fd5b505050506040513d6020811015614eaf57600080fd5b505190506000614ebf8483614a48565b90506000614ed3856142c688612710614f0b565b90506000614ef4836142c66005546127100188614f0b90919063ffffffff16565b919091109f9e505050505050505050505050505050565b600082614f1a575060006127df565b82820282848281614f2757fe5b04146137985760405162461bcd60e51b81526004018080602001828103825260218152602001806154316021913960400191505060405180910390fd5b6000808211614fba576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381614fc357fe5b049392505050565b6060613795848460008585614fdf856150f0565b615030576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b6020831061506e5780518252601f19909201916020918201910161504f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146150d0576040519150601f19603f3d011682016040523d82523d6000602084013e6150d5565b606091505b50915091506150e58282866150f6565b979650505050505050565b3b151590565b60608315615105575081613798565b8251156151155782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561515f578181015183820152602001615147565b50505050905090810190601f16801561518c5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50805460008255906000526020600020908101906151b89190615220565b50565b828054828255906000526020600020908101928215615210579160200282015b8281111561521057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906151db565b5061521c929150615220565b5090565b5b8082111561521c576000815560010161522156fe506f736974696f6e526f757465723a20696e76616c696420657865637574696f6e4665655265656e7472616e637947756172643a207265656e7472616e742063616c6c00506f736974696f6e526f757465723a20696e76616c6964206d73672e76616c75654f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373506f736974696f6e526f757465723a206d617854696d6544656c617920697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e73756666696369656e7420616d6f756e744f7574506f736974696f6e526f757465723a20696e637265617365506f736974696f6e526571756573744b657973537461727420697320746f6f2068696768506f736974696f6e526f757465723a206d696e426c6f636b44656c61794b656570657220697320746f6f2068696768506f736974696f6e526f757465723a20696e76616c6964205f70617468206c656e67746842617365506f736974696f6e4d616e616765723a206d61726b207072696365206c6f776572207468616e206c696d697442617365506f736974696f6e4d616e616765723a206465706f73697446656520697320746f6f206869676842617365506f736974696f6e4d616e616765723a206d696e54696d6544656c61795075626c696320697320746f6f2068696768536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657242617365506f736974696f6e4d616e616765723a206d61726b20707269636520686967686572207468616e206c696d6974506f736974696f6e526f757465723a206d696e457865637574696f6e46656520697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e637265617365506f736974696f6e42756666657242707320697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e76616c6964205f706174682e6c656e677468506f736974696f6e526f757465723a206465637265617365506f736974696f6e526571756573744b657973537461727420697320746f6f206869676842617365506f736974696f6e4d616e616765723a20696e76616c69642073656e6465725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564506f736974696f6e526f757465723a2063616c6c6572206973206e6f742074686520706f736974696f6e206b6565706572506f736974696f6e526f757465723a207265717565737420686173206578706972656442617365506f736974696f6e4d616e616765723a204f6e6c792050686c704d616e616765722063616e20776974686472617720666565a2646970667358221220db5c7d6bcf347f36e6f5c8a74b98d7af148e702fa0b3c420a62461ba89809bd364736f6c63430007060033