false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here

Contract Address Details

0xF22BFBe1725ec046D30987E9af423b6fA9FD637B

Contract Name
OrderManager
Creator
0x3b74e7–cd70b1 at 0xf325ab–3d866e
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
67 Transactions
Transfers
96 Transfers
Gas Used
17,789,336
Last Balance Update
486607
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
OrderManager




Optimization enabled
true
Compiler version
v0.8.19+commit.7dd6d404




Optimization runs
200
EVM Version
paris




Verified at
2024-07-10T10:47:57.581739Z

Constructor Arguments

0x000000000000000000000000082321f9939373b02ad54ea214bf6e822531e679000000000000000000000000ed2f56432a9af01328ca53b4dc1c8ec822869f9a00000000000000000000000011905d2def1071c84e6f835d16e220066d092df900000000000000000000000000000000000000000000000000016bcc41e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000090f560000000000000000000000000000000000000000000000000000000000090f560

Arg [0] (address) : 0x082321f9939373b02ad54ea214bf6e822531e679
Arg [1] (address) : 0xed2f56432a9af01328ca53b4dc1c8ec822869f9a
Arg [2] (address) : 0x11905d2def1071c84e6f835d16e220066d092df9
Arg [3] (uint256) : 400000000000000
Arg [4] (uint256) : 0
Arg [5] (uint256) : 10
Arg [6] (uint256) : 5
Arg [7] (uint256) : 9500000
Arg [8] (uint256) : 9500000

              

src/contracts/core/OrderManager.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

import '../libraries/token/SafeERC20.sol';
import '../libraries/utils/ReentrancyGuard.sol';
import '../libraries/token/IERC20.sol';
import './BaseOrderManager.sol';
import './interfaces/IOrderManager.sol';
import '../libraries/utils/EnumerableSet.sol';
import "./../libraries/utils/Structs.sol";
import "../libraries/utils/Structs.sol";

contract OrderManager is
    BaseOrderManager,
    IOrderManager,
    ReentrancyGuard
{
    using SafeERC20 for IERC20;

    uint256 public minExecutionFeeIncreaseMarketOrder;
    uint256 public minExecutionFeeDecreaseMarketOrder;
    uint256 public minExecutionFeeIncreaseLimitOrder;
    uint256 public minExecutionFeeDecreaseLimitOrder;
    mapping(address => uint256) public increasePositionsIndex;
    mapping(bytes32 => StructsUtils.IncreasePositionRequest) public increasePositionRequests;
    bytes32[] public increasePositionRequestKeys;
    mapping(address => uint256) public decreasePositionsIndex;
    mapping(bytes32 => StructsUtils.DecreasePositionRequest) public decreasePositionRequests;
    bytes32[] decreasePositionRequestKeys;
    mapping(address => bool) public isPositionKeeper;
    uint256 public minBlockDelayKeeper;
    uint256 public minTimeDelayPublic;
    uint256 public maxTimeDelay;
    uint256 public increasePositionRequestKeysStart;
    uint256 public decreasePositionRequestKeysStart;

    mapping (bytes32 => StructsUtils.Order) public orders;
    EnumerableSet.Bytes32Set private orderKeys;
    mapping (address => uint256) public ordersIndex;
    mapping (address => bool) public isOrderKeeper;
    mapping (address => bool) public isLiquidator;
    uint public maxProfitMultiplier;

    uint256 public minPurchaseUSDAmountMarketOrder;//this will be in 10^18 
    uint256 public minPurchaseUSDAmountLimitOrder;// this will be in 10^18

    event CreateIncreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 amountIn,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 index,
        uint256 queueIndex,
        uint256 blockNumber,
        uint256 blockTime,
        uint256 gasPrice
    );

    event CancelIncreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 amountIn,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CreateDecreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 index,
        uint256 queueIndex,
        uint256 blockNumber,
        uint256 blockTime
    );

    event ExecuteDecreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CancelDecreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 sizeDelta,
        bool isLong,
        address receiver,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event ExecuteIncreasePosition(
        address indexed account,
        address _collateralToken,
        address indexToken,
        uint256 amountIn,
        uint256 sizeDelta,
        bool isLong,
        uint256 acceptablePrice,
        uint256 executionFee,
        uint256 blockGap,
        uint256 timeGap
    );

    event CreateOrder(
        address indexed account,
        address collateralToken,
        address indexToken,
        uint256 orderIndex,
        uint256 collateralDelta,
        uint256 sizeDelta,
        uint256 triggerPrice,
        uint256 executionFee,
        bool isLong,
        bool triggerAboveThreshold,
        bool indexed isIncreaseOrder,
        bool isMaxOrder
    );

    event UpdateOrder(
        address indexed account,
        address collateralToken,
        address indexToken,
        uint256 orderIndex,
        uint256 collateralDelta,
        uint256 sizeDelta,
        uint256 triggerPrice,
        bool isLong,
        bool triggerAboveThreshold,
        bool indexed isIncreaseOrder,
        bool isMaxOrder
    );

    event CancelOrder(
        address indexed account,
        address collateralToken,
        address indexToken,
        uint256 orderIndex,
        uint256 collateralDelta,
        uint256 sizeDelta,
        uint256 triggerPrice,
        uint256 executionFee,
        bool isLong,
        bool triggerAboveThreshold,
        bool indexed isIncreaseOrder,
        bool isMaxOrder
    );
    event ExecuteOrder(
        address indexed account,
        address collateralToken,
        address indexToken,
        uint256 orderIndex,
        uint256 collateralDelta,
        uint256 sizeDelta,
        uint256 triggerPrice,
        uint256 executionFee,
        uint256 executionPrice,
        bool isLong,
        bool triggerAboveThreshold,
        bool indexed isIncreaseOrder
    );

    event SetPositionKeeper(address indexed account, bool isActive);
    event SetOrderKeeper(address indexed account, bool isActive);
    event SetLiquidator(address indexed account, bool isActive);

    event SetDelayValues(
        uint256 minBlockDelayKeeper,
        uint256 minTimeDelayPublic,
        uint256 maxTimeDelay
    );

    constructor(
        address _vault,
        address _utils,
        address _pricefeed,
        uint256 _minExecutionFeeMarketOrder,
        uint256 _minExecutionFeeLimitOrder,
        uint _depositFee,
        uint _maxProfitMultiplier,
        uint256 _minPurchaseUSDAmountLimitOrder,
        uint256 _minPurchaseUSDAmountMarketOrder
    ) BaseOrderManager(_vault, _utils, _pricefeed, _depositFee) {
        minExecutionFeeIncreaseMarketOrder = _minExecutionFeeMarketOrder;
        minExecutionFeeDecreaseMarketOrder = _minExecutionFeeMarketOrder;
        minExecutionFeeIncreaseLimitOrder = _minExecutionFeeLimitOrder;
        minExecutionFeeDecreaseLimitOrder = _minExecutionFeeLimitOrder;
        maxProfitMultiplier = _maxProfitMultiplier;
        minPurchaseUSDAmountMarketOrder = _minPurchaseUSDAmountMarketOrder;
        minPurchaseUSDAmountLimitOrder = _minPurchaseUSDAmountLimitOrder;
    }

    modifier onlyPositionKeeper() {
        require(isPositionKeeper[msg.sender], "OM:403");
        _;
    }

    modifier onlyLiquidator() {
        require(isLiquidator[msg.sender], "OM:403");
        _;
    }

    modifier onlyOrderKeeper() {
        require(isOrderKeeper[msg.sender], "OM:403");
        _;
    }
    function setMinPurchaseAmount(uint256 _marketOrder ,uint256 _limitOrder) external onlyAdmin {
        minPurchaseUSDAmountMarketOrder = _marketOrder;
        minPurchaseUSDAmountLimitOrder = _limitOrder;
    }

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

    function setMaxTPMultiplier(uint _maxProfitMultiplier) external onlyAdmin {
        maxProfitMultiplier = _maxProfitMultiplier;
    }

    function setMinExecutionFeeMarketOrder(
        uint256 _minExecutionFeeIncreaseMarketOrder,
        uint256 _minExecutionFeeDecreaseMarketOrder
    ) external onlyAdmin {
        minExecutionFeeIncreaseMarketOrder = _minExecutionFeeIncreaseMarketOrder;
        minExecutionFeeDecreaseMarketOrder = _minExecutionFeeDecreaseMarketOrder;
    }

    function setMinExecutionFeeLimitOrder(
        uint256 _minExecutionFeeIncreaseLimitOrder,
        uint256 _minExecutionFeeDecreaseLimitOrder
    ) external onlyAdmin {
        minExecutionFeeIncreaseLimitOrder = _minExecutionFeeIncreaseLimitOrder;
        minExecutionFeeDecreaseLimitOrder = _minExecutionFeeDecreaseLimitOrder;
    }

    function setPriceFeed(address _priceFeed) override external onlyAdmin {
        pricefeed = _priceFeed;
    }

    function setDelayValues(
        uint256 _minBlockDelayKeeper,
        uint256 _minTimeDelayPublic,
        uint256 _maxTimeDelay
    ) external onlyAdmin {
        minBlockDelayKeeper = _minBlockDelayKeeper;
        minTimeDelayPublic = _minTimeDelayPublic;
        maxTimeDelay = _maxTimeDelay;
        emit SetDelayValues(
            _minBlockDelayKeeper,
            _minTimeDelayPublic,
            _maxTimeDelay
        );
    }

    function setOrderKeeper(address _account, bool _isActive) external onlyAdmin {
        isOrderKeeper[_account] = _isActive;
        emit SetOrderKeeper(_account, _isActive);
    }

    function setLiquidator(address _account, bool _isActive) external onlyAdmin {
        isLiquidator[_account] = _isActive;
        emit SetLiquidator(_account, _isActive);
    }

    function createIncreasePosition(
        address _collateralToken,
        address _indexToken,
        uint256 _amountIn,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 takeProfitPrice,
        uint256 stopLossPrice,
        uint256 _executionFee
    ) external payable nonReentrant returns (bytes32) {
        require(!IVault(vault).ceaseTradingActivity(), "OM:0");
        require(IVault(vault).canBeIndexToken(_indexToken), "OM:idx");
        require(_executionFee == msg.value, "OM:ef");
        if (takeProfitPrice == 0 && stopLossPrice == 0) {
            require(
                _executionFee >=
                    minExecutionFeeIncreaseMarketOrder,
                "OM:ef"
            );
        } else if (takeProfitPrice != 0 && stopLossPrice != 0) {
            require(
                _executionFee >=
                    minExecutionFeeIncreaseMarketOrder +
                        2 *
                        minExecutionFeeDecreaseLimitOrder,
                "OM:ef"
            );
        } else {
            require(
                _executionFee >=
                    minExecutionFeeIncreaseMarketOrder +
                        1 *
                        minExecutionFeeDecreaseLimitOrder,
                "OM:ef"
            );
        }
        require( _amountIn>= minPurchaseUSDAmountMarketOrder, "OM:c");
        IERC20(_collateralToken).safeTransferFrom(msg.sender, address(this), _amountIn);
        bytes32 positionKey =  _createIncreasePosition(
            msg.sender,
            _collateralToken,
            _indexToken,
            _amountIn,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            minExecutionFeeIncreaseMarketOrder
        );
        if (takeProfitPrice != 0) {
            _createOrder(
                msg.sender,
                0,
                _collateralToken,
                _indexToken,
                _sizeDelta,
                _isLong,
                takeProfitPrice,
                _isLong,
                minExecutionFeeDecreaseLimitOrder,
                false,
                false
            );
        }
        if (stopLossPrice != 0) {
            _createOrder(
                msg.sender,
                0,
                _collateralToken,
                _indexToken,
                _sizeDelta,
                _isLong,
                stopLossPrice,
                !_isLong,
                minExecutionFeeDecreaseLimitOrder,
                false,
                false
            );
        }

        return positionKey;
    }

    function _createIncreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _amountIn,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 _executionFee
    ) internal returns (bytes32) {
        StructsUtils.IncreasePositionRequest memory request = StructsUtils.IncreasePositionRequest(
                _account,
                _collateralToken,
                _indexToken,
                _amountIn,
                _sizeDelta,
                _isLong,
                _acceptablePrice,
                _executionFee,
                block.number,
                block.timestamp
            );

        (uint256 index, bytes32 requestKey) = _storeIncreasePositionRequest(
            request
        );
        emit CreateIncreasePosition(
            _account,
            _collateralToken,
            _indexToken,
            _amountIn,
            _sizeDelta,
            _isLong,
            _acceptablePrice,
            _executionFee,
            index,
            increasePositionRequestKeys.length - 1,
            block.number,
            block.timestamp,
            tx.gasprice
        );
        return requestKey;
    }

    function cancelIncreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        StructsUtils.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;
        }

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

        delete increasePositionRequests[_key];
        IERC20(request._collateralToken).safeTransfer(request.account, request.amountIn);
        (bool success,  ) = _executionFeeReceiver.call{value: request.executionFee}("");
        require(success, "OM:f");

        emit CancelIncreasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.amountIn,
            request.sizeDelta,
            request.isLong,
            request.acceptablePrice,
            request.executionFee,
            block.number - request.blockNumber,
            block.timestamp - request.blockTime
        );
        return true;
    }

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

        if (index >= length) {
            return index;
        }

        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 {
                    continue;
                }
            }

            delete increasePositionRequestKeys[index];
            index++;
        }

        increasePositionRequestKeysStart = index;
        return index;
    }

    function executeIncreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        StructsUtils.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;
        }

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

        delete increasePositionRequests[_key];
        IERC20(request._collateralToken).safeTransfer(vault, _collectFees(request.account, request._collateralToken, request.amountIn, request.indexToken, request.isLong, request.sizeDelta));

        _increasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            request.acceptablePrice
        );

        (bool success,  ) = _executionFeeReceiver.call{value: request.executionFee}("");
        require(success, "OM:f");

        if (request.sizeDelta > 0) {
            uint256 tpPrice = IUtils(utils).getTPPrice(
                request.sizeDelta,
                request.isLong,
                request.acceptablePrice,
                request.amountIn * maxProfitMultiplier,
                request._collateralToken
            );
            _createOrder(
                request.account,
                0,
                request._collateralToken,
                request.indexToken,
                request.sizeDelta,
                request.isLong,
                tpPrice,
                request.isLong,
                minExecutionFeeDecreaseLimitOrder,
                false,
                true
            );
        }

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

        return true;
    }

    function _storeIncreasePositionRequest(
        StructsUtils.IncreasePositionRequest memory _request
    ) internal returns (uint256, bytes32) {
        address account = _request.account;
        uint256 index = increasePositionsIndex[account] + 1;
        increasePositionsIndex[account] = index;
        bytes32 key = getRequestKey(account, index);

        increasePositionRequests[key] = _request;
        increasePositionRequestKeys.push(key);

        return (index, key);
    }

    function createDecreasePosition(
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _acceptablePrice,
        uint256 _executionFee
    ) external payable nonReentrant returns (bytes32) {
        require(!IVault(vault).ceaseTradingActivity(), "OM:0");
        require(_executionFee >= minExecutionFeeDecreaseMarketOrder, "OM:f");
        require(_executionFee == msg.value, "OM:ef");
        require(checkSufficientPositionExists(msg.sender, _collateralToken, _indexToken,_isLong, _sizeDelta), "OM:size");

        return
            _createDecreasePosition(
                msg.sender,
                _collateralToken,
                _indexToken,
                _sizeDelta,
                _isLong,
                _receiver,
                _acceptablePrice,
                _executionFee
            );
    }

    function _createDecreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _acceptablePrice,
        uint256 _executionFee
    ) internal returns (bytes32) {
        StructsUtils.DecreasePositionRequest memory request = StructsUtils.DecreasePositionRequest(
                _account,
                _collateralToken,
                _indexToken,
                _sizeDelta,
                _isLong,
                _receiver,
                _acceptablePrice,
                _executionFee,
                block.number,
                block.timestamp
            );

        (uint256 index, bytes32 requestKey) = _storeDecreasePositionRequest(
            request
        );
        emit CreateDecreasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            request.receiver,
            request.acceptablePrice,
            request.executionFee,
            index,
            decreasePositionRequestKeys.length - 1,
            block.number,
            block.timestamp
        );
        return requestKey;
    }

    function _storeDecreasePositionRequest(
        StructsUtils.DecreasePositionRequest memory _request
    ) internal returns (uint256, bytes32) {
        address account = _request.account;
        uint256 index = decreasePositionsIndex[account] + 1;
        decreasePositionsIndex[account] = index;
        bytes32 key = getRequestKey(account, index);

        decreasePositionRequests[key] = _request;
        decreasePositionRequestKeys.push(key);

        return (index, key);
    }

    function cancelDecreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        StructsUtils.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;
        }

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

        delete decreasePositionRequests[_key];

        (bool success,  ) = _executionFeeReceiver.call{value: request.executionFee}("");
        require(success, "OM:f");

        emit CancelDecreasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            request.receiver,
            request.acceptablePrice,
            request.executionFee,
            block.number - request.blockNumber,
            block.timestamp - request.blockTime
        );

        return true;
    }

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

        if (index >= length) {
            return index;
        }

        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 {
                    continue;
                }
            }

            delete decreasePositionRequestKeys[index];
            index++;
        }

        decreasePositionRequestKeysStart = index;
        return index;
    }

    function executeDecreasePosition(
        bytes32 _key,
        address payable _executionFeeReceiver
    ) public nonReentrant returns (bool) {
        StructsUtils.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;
        }

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

        delete decreasePositionRequests[_key];

        uint256 amountOut = _decreasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            address(this),
            request.acceptablePrice
        );

        IERC20(request._collateralToken).safeTransfer(
            request.receiver,
            amountOut
        );

        (bool success, ) = _executionFeeReceiver.call{value: request.executionFee}("");
        require(success, "OM:f");

        emit ExecuteDecreasePosition(
            request.account,
            request._collateralToken,
            request.indexToken,
            request.sizeDelta,
            request.isLong,
            request.receiver,
            request.acceptablePrice,
            request.executionFee,
            block.number - (request.blockNumber),
            block.timestamp - (request.blockTime)
        );
        return true;
    }

    function _validateExecution(
        uint256 _positionBlockNumber,
        uint256 _positionBlockTime,
        address _account
    ) internal view returns (bool) {
        require(
            block.timestamp < _positionBlockTime + (maxTimeDelay),
            "OM:exp"
        );

        return
            _validateExecutionOrCancellation(
                _positionBlockNumber,
                _positionBlockTime,
                _account
            );
    }

    function _validateCancellation(
        uint256 _positionBlockNumber,
        uint256 _positionBlockTime,
        address _account
    ) internal view returns (bool) {
        return
            _validateExecutionOrCancellation(
                _positionBlockNumber,
                _positionBlockTime,
                _account
            );
    }

    function _validateExecutionOrCancellation(
        uint256 _positionBlockNumber,
        uint256 _positionBlockTime,
        address _account
    ) internal view returns (bool) {

        if (msg.sender == address(this) || isPositionKeeper[msg.sender]) {
            return _positionBlockNumber + minBlockDelayKeeper <= block.number;
        }
        require(msg.sender == _account, "OM:403");

        require(
            _positionBlockTime + minTimeDelayPublic <= block.timestamp,
            "OM:d"
        );

        return true;
    }

    function getRequestKey(
        address account,
        uint256 index
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(account, index));
    }

    // If a user by-mistake sends token directly to the OM, we can use this function to refund to the user
    function retrieveStuckFunds(address _token, uint256 _amount) external onlyAdmin {
        require(_amount <= IERC20(_token).balanceOf(address(this)),"OM:amount");
        IERC20(_token).safeTransfer(admin, _amount);
    }

    function validatePositionOrderPrice(
        bool _triggerAboveThreshold,
        uint256 _triggerPrice,
        address _indexToken,
        bool /*_maximizePrice*/
    ) public view returns (uint256, bool) {
        uint256 currentPrice = IPriceFeed(pricefeed).getPriceOfToken(_indexToken);
        bool isPriceValid = _triggerAboveThreshold ? currentPrice > _triggerPrice : currentPrice < _triggerPrice;
        require(isPriceValid, "OM:pr");
        return (currentPrice, isPriceValid);
    }

    function createOrders(
        uint256 collateralDelta,
        address indexToken,
        uint256 sizeDelta,
        address collateralToken,
        bool isLong,
        uint256 _executionFee,
        uint256 limitPrice,
        uint256 tpPrice,
        uint256 slPrice
    ) external payable nonReentrant {
        require(!IVault(vault).ceaseTradingActivity(), "OM:0");
        require(IVault(vault).canBeIndexToken(indexToken), "OM:idx");
        require(msg.value == _executionFee, "OM:ef");

        // to make sure that you can either open a limit order or tp or sl order
        if(tpPrice !=0 || slPrice !=0){
            require(limitPrice == 0, "OM:fail");
        }
        if (tpPrice != 0 && slPrice != 0) {
            require(
                _executionFee >= 2 * minExecutionFeeDecreaseLimitOrder,
                "OM:f"
            );
        } else if (limitPrice != 0) {
            require(
                _executionFee >=
                    minExecutionFeeIncreaseLimitOrder,
                "OM:f"
            );
        } else {
            require(_executionFee >= minExecutionFeeDecreaseLimitOrder, "OM:f");
        }

        {
            uint256 _collateralDelta = collateralDelta;
            address _indexToken = indexToken;
            uint256 _sizeDelta = sizeDelta;
            address _collateralToken = collateralToken;
            bool _isLong = isLong;
            uint256 _limitPrice = limitPrice;
            uint256 _tpPrice= tpPrice;
            uint256 _slPrice= slPrice;

            if(limitPrice != 0){

                    IERC20(_collateralToken).safeTransferFrom(msg.sender, address(this), _collateralDelta);
                require(
                    _collateralDelta >= minPurchaseUSDAmountLimitOrder,
                    "OM:c"
                );
                _createOrder(
                    msg.sender,
                    _collateralDelta,
                    _collateralToken,
                    _indexToken,
                    _sizeDelta,
                    _isLong,
                    _limitPrice,
                    !_isLong,
                    minExecutionFeeIncreaseLimitOrder,
                    true,
                    false
                );
            } else {
                if (tpPrice != 0) {
                    _createOrder(
                        msg.sender,
                        0,
                        _collateralToken,
                        _indexToken,
                        _sizeDelta,
                        _isLong,
                        _tpPrice,
                        _isLong,
                        minExecutionFeeDecreaseLimitOrder,
                        false,
                        false
                    );
                }
                if (slPrice != 0) {
                    _createOrder(
                        msg.sender,
                        0,
                        _collateralToken,
                        _indexToken,
                        _sizeDelta,
                        _isLong,
                        _slPrice,
                        !_isLong,
                        minExecutionFeeDecreaseLimitOrder,
                        false,
                        false
                    );
                }
            }
        }
    }

    function _createOrder(
        address _account,
        uint256 _collateralDelta,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold,
        uint256 _executionFee,
        bool _isIncreaseOrder,
        bool _isMaxOrder
    ) private {

        {
            address account = _account;
            uint256 collateralDelta = _collateralDelta;
            address collateralToken = _collateralToken;
            address indexToken = _indexToken;
            uint256 sizeDelta = _sizeDelta;
            bool isLong = _isLong;
            uint256 triggerPrice = _triggerPrice;
            bool triggerAboveThreshold = _triggerAboveThreshold;
            uint256 executionFee = _executionFee;
            bool isIncreaseOrder = _isIncreaseOrder;
            bool isMaxOrder = _isMaxOrder;

            uint256 _orderIndex = ordersIndex[account];
            ordersIndex[account] = _orderIndex+(1);
            bytes32 orderKey = getOrderKey(account,_orderIndex);
            orders[orderKey] = StructsUtils.Order(
                account,
                collateralToken,
                indexToken,
                collateralDelta,
                sizeDelta,
                triggerPrice,
                executionFee,
                isLong,
                triggerAboveThreshold,
                isIncreaseOrder,
                isMaxOrder,
                _orderIndex,
                block.timestamp
            );
            EnumerableSet.add(orderKeys, orderKey);

            emitOrderCreateEvent(account, _orderIndex);
        }
        
    }

    function emitOrderCreateEvent(address _account, uint256 idx) internal{
        StructsUtils.Order memory order = orders[getOrderKey(_account,idx)];
        emit CreateOrder(
            _account,
            order.collateralToken,
            order.indexToken,
            idx,
            order.collateralDelta,
            order.sizeDelta,
            order.triggerPrice,
            order.executionFee,
            order.isLong,
            order.triggerAboveThreshold,
            order.isIncreaseOrder,
            order.isMaxOrder
        );
        emit UpdateOrder(
            _account,
            order.collateralToken,
            order.indexToken,
            idx,
            order.collateralDelta,
            order.sizeDelta,
            order.triggerPrice,
            order.isLong,
            order.triggerAboveThreshold,
            order.isIncreaseOrder,
            order.isMaxOrder
        );
    }

    function updateOrder(uint256 _orderIndex, uint256 _sizeDelta, uint256 _newCollateralAmount,  uint256 _triggerPrice) external nonReentrant {
        StructsUtils.Order storage order = orders[getOrderKey(msg.sender,_orderIndex)];
        require(order.account != address(0), "OM:fail");

        uint256 oldCollateralAmount = order.collateralDelta;
        if(order.isIncreaseOrder){
            require(_newCollateralAmount >= minPurchaseUSDAmountLimitOrder, "OM:c");
            bool increaseCollateral = _newCollateralAmount > oldCollateralAmount;
            uint256 collateralDelta = increaseCollateral ? (_newCollateralAmount - oldCollateralAmount) : (oldCollateralAmount - _newCollateralAmount);
            if(increaseCollateral){
                IERC20(order.collateralToken).safeTransferFrom(msg.sender, address(this), collateralDelta);
            }
            else{
                IERC20(order.collateralToken).safeTransfer(order.account, collateralDelta);
            }
            order.collateralDelta = _newCollateralAmount;
        }

        order.triggerPrice = _triggerPrice;
        order.sizeDelta = _sizeDelta;

        emit UpdateOrder(
            msg.sender,
            order.collateralToken,
            order.indexToken,
            _orderIndex,
            order.collateralDelta,
            order.sizeDelta,
            order.triggerPrice,
            order.isLong,
            order.triggerAboveThreshold,
            order.isIncreaseOrder,
            order.isMaxOrder
        );
    }

    function cancelOrder(uint256 _orderIndex, address account) public nonReentrant() {
        bytes32 orderKey = getOrderKey(account,_orderIndex);
        StructsUtils.Order memory order = orders[orderKey];

        if(order.isMaxOrder){
            require(isOrderKeeper[msg.sender], "OM:403");
        }
        else{
            require(msg.sender == account || isOrderKeeper[msg.sender], "OM:403");
        }
        _cancelOrder(orderKey, _orderIndex,  order, msg.sender);
    }

    function _cancelOrder(bytes32 orderKey, uint256 _orderIndex, StructsUtils.Order memory order, address feeReceiver) internal {
        require(order.account != address(0), "OM:fail");
        delete orders[orderKey];
        EnumerableSet.remove(orderKeys, orderKey);
        if(order.isIncreaseOrder){
            IERC20(order.collateralToken).safeTransfer(order.account, order.collateralDelta);
        }
        if (!(order.isMaxOrder)) {
        (bool success,  ) = payable(feeReceiver).call{value: order.executionFee}("");
        require(success, "OM:f");
        }

        emit CancelOrder(
            order.account,
            order.collateralToken,
            order.indexToken,
            _orderIndex,
            order.collateralDelta,
            order.sizeDelta,
            order.triggerPrice,
            order.executionFee,
            order.isLong,
            order.triggerAboveThreshold,
            order.isIncreaseOrder,
            order.isMaxOrder
        );

        emit UpdateOrder(
            order.account,
            order.collateralToken,
            order.indexToken,
            _orderIndex,
            0,
            0,
            0,
            false,
            false,
            false,
            order.isMaxOrder
        );
    }

    function executeOrder(address _address, uint256 _orderIndex, address payable _feeReceiver) override public nonReentrant onlyOrderKeeper {
        bytes32 orderKey = getOrderKey(_address,_orderIndex);
        StructsUtils.Order memory order = orders[orderKey];
        require(order.account != address(0), "OM:fail");

        // increase long should use max pr
        // increase short should use min pr
        (uint256 currentPrice, ) = validatePositionOrderPrice(
            order.triggerAboveThreshold,
            order.triggerPrice,
            order.indexToken,
            order.isLong
        );

        if(order.isIncreaseOrder){
            IERC20(order.collateralToken).safeTransfer(vault, order.collateralDelta);
            IVault(vault).increasePosition(order.account, order.collateralToken, order.indexToken, order.sizeDelta, order.isLong);
            if(order.sizeDelta > 0){
                uint tpPrice = IUtils(utils).getTPPrice(
                    order.sizeDelta,
                    order.isLong,
                    order.triggerPrice,
                    order.collateralDelta * maxProfitMultiplier,
                    order.collateralToken
                );
                _createOrder(
                    order.account,
                    0,
                    order.collateralToken,
                    order.indexToken,
                    order.sizeDelta,
                    order.isLong,
                    tpPrice,
                    order.isLong,
                    minExecutionFeeDecreaseLimitOrder,
                    false,
                    true
                );
            }
        } else{
            bool sufficientSizeExists = checkSufficientPositionExists(order.account, order.collateralToken, order.indexToken, order.isLong, order.sizeDelta);
            if(!sufficientSizeExists){
                _cancelOrder(orderKey, _orderIndex, order, _feeReceiver);
                return;
            }
            uint256 amountOut = IVault(vault).decreasePosition(order.account, order.collateralToken, order.indexToken, order.sizeDelta, order.isLong, address(this));
            IERC20(order.collateralToken).safeTransfer(order.account, amountOut);
        }

        delete orders[orderKey];
        EnumerableSet.remove(orderKeys, orderKey);

        // pay executor
        (bool success,  ) = _feeReceiver.call{value: order.executionFee}("");
        require(success, "OM:f");

        emit ExecuteOrder(
            order.account,
            order.collateralToken,
            order.indexToken,
            _orderIndex,
            order.collateralDelta,
            order.sizeDelta,
            order.triggerPrice,
            order.executionFee,
            currentPrice,
            order.isLong,
            order.triggerAboveThreshold,
            order.isIncreaseOrder
        );
        emit UpdateOrder(
            order.account,
            order.collateralToken,
            order.indexToken,
            _orderIndex,
            0,
            0,
            0,
            false,
            false,
            false,
            order.isMaxOrder
        );
    }

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

    function getAllOrders() public view returns(StructsUtils.Order[] memory){
        uint orderLength = EnumerableSet.length(orderKeys);
        StructsUtils.Order[] memory openOrders = new StructsUtils.Order[](orderLength);
        for(uint i =0;i<orderLength;i++){
            openOrders[i] = (orders[EnumerableSet.at(orderKeys, i)]);
        }
        return openOrders;
    }

    function executeMultipleOrders(address[] calldata accountAddresses, uint[] calldata orderIndices, address payable _feeReceiver) public onlyOrderKeeper {
        uint length = accountAddresses.length;
        for(uint i=0;i<length;i++){
            try this.executeOrder(accountAddresses[i], orderIndices[i], _feeReceiver){} catch {}
        }
    }

    function liquidateMultiplePositions(bytes32[] calldata keys, address payable _feeReceiver) public onlyLiquidator {
        uint length = keys.length;
        for(uint i=0;i<length;i++){
            try IVault(vault).liquidatePosition(keys[i],_feeReceiver){} catch{}
        }
    }

    function checkSufficientPositionExists(address account, address collateralToken, address indexToken, bool isLong, uint sizeDelta) private view returns(bool) {
        StructsUtils.Position memory position = IVault(vault).getPosition(account, collateralToken, indexToken, isLong);
        if(position.size < sizeDelta){
            return false;
        }
        return true;
    }

    function getIncreasePositionCount() public view returns(uint){
        return increasePositionRequestKeys.length;
    }
    function getDecreasePositionCount() public view returns(uint){
        return decreasePositionRequestKeys.length;
    }

    function getIncreasePositionRequestFromIndex(uint256 index) external view returns(StructsUtils.IncreasePositionRequest memory){
       require(index < increasePositionRequestKeys.length, "OM:fail");
       require(increasePositionRequestKeys[index] != bytes32(0), "OM:fail");

         return increasePositionRequests[increasePositionRequestKeys[index]];
    }
}
        

src/contracts/access/Governable.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

contract Governable {
    address public gov;

    constructor() {
        gov = msg.sender;
    }

    modifier onlyGov() {
        require(msg.sender == gov, "Governable: forbidden");
        _;
    }

    function setGov(address _gov) external onlyGov {
        gov = _gov;
    }
}
          

src/contracts/core/BaseOrderManager.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

import '../libraries/token/SafeERC20.sol';
import '../libraries/token/IERC20.sol';
import './interfaces/IVault.sol';
import './interfaces/IUtils.sol';
import './interfaces/ITimeLock.sol';
import '../access/Governable.sol';
import '../libraries/utils/ReentrancyGuard.sol';
import './interfaces/IPriceFeed.sol';
import "../libraries/utils/Structs.sol";


contract BaseOrderManager{
    using SafeERC20 for IERC20;

    address public admin;
    address public vault;
    address public utils;
    address public pricefeed;

    uint256 public constant BASIS_POINTS_DIVISOR = 10000;
    uint256 public increasePositionBufferBps = 100;
    mapping (address => uint256) public feeReserves;
    uint public depositFee;

    event LeverageDecreased(
        uint256 collateralDelta,
        uint256 prevLeverage,
        uint256 nextLeverage
    );
    event WithdrawFees(address token, address receiver, uint256 amount);


    modifier onlyAdmin() {
        require(msg.sender == admin, "BM:403");
        _;
    }

    constructor(
        address _vault,
        address _utils,
        address _pricefeed,
        uint _depositFee
    ) {
        vault = _vault;
        utils = _utils;
        pricefeed = _pricefeed;
        admin = msg.sender;
        depositFee = _depositFee;
    }

    function setAdmin(address _admin) external onlyAdmin {
        admin = _admin;
    }

    function setVault(address _vault) external onlyAdmin {
        vault = _vault;
    }
    
    function setUtils(address _utils) external onlyAdmin {
        utils = _utils;
    }

    function setDepositFee(uint _fee) external onlyAdmin {
        depositFee = _fee;
    }

    function _increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong, uint256 acceptablePrice) internal {
        uint256 markPrice = _isLong ? IPriceFeed(pricefeed).getMaxPriceOfToken(_indexToken) : IPriceFeed(pricefeed).getMinPriceOfToken(_indexToken);
        if (_isLong) {
            require(markPrice <= acceptablePrice, "BM:mp");
        } else {
            require(markPrice >= acceptablePrice, "BM:mp");
        }

        IVault(vault).increasePosition(_account, _collateralToken, _indexToken, _sizeDelta, _isLong);
    }

    function _decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong, address _receiver, uint256 _price) internal returns (uint256) {
        uint256 markPrice = _isLong ? IPriceFeed(pricefeed).getMinPriceOfToken(_indexToken) : IPriceFeed(pricefeed).getMaxPriceOfToken(_indexToken);
        if (_isLong) {
            require(markPrice >= _price, "BM:mp");
        } else {
            require(markPrice <= _price, "BM:mp");
        }
        return IVault(vault).decreasePosition(_account, _collateralToken, _indexToken, _sizeDelta, _isLong, _receiver);
    }

    function shouldDeductFee(
        address _account,
        address collateralToken,
        uint256 _amountIn,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta,
        uint256 _increasePositionBufferBps
    ) private returns (bool) {

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

        StructsUtils.Position memory position = IVault(vault).getPosition(_account, collateralToken, _indexToken, _isLong);
        uint256 size = position.size;
        uint256 collateral = position.collateral;

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

        uint256 nextSize = size+(_sizeDelta);
        uint256 collateralDelta = IUtils(utils).tokenToUsdMin(collateralToken, _amountIn);
        uint256 nextCollateral = collateral+(collateralDelta);

        uint256 prevLeverage = size*(BASIS_POINTS_DIVISOR)/(collateral);
        // allow for a maximum of a increasePositionBufferBps decrease since there might be some swap fees taken from the collateral
        uint256 nextLeverage = nextSize*(BASIS_POINTS_DIVISOR + _increasePositionBufferBps)/(nextCollateral);
        if(nextLeverage < prevLeverage){
            emit LeverageDecreased(collateralDelta, prevLeverage, nextLeverage);
            return true;
        }

        return false;
    }

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

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

    function _collectFees(
        address _account,
        address collateralToken,
        uint256 _amountIn,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) internal returns (uint256) {

        if (shouldDeductFee(_account,collateralToken,_amountIn,_indexToken,_isLong,_sizeDelta,increasePositionBufferBps)) {
            uint256 afterFeeAmount = _amountIn*(BASIS_POINTS_DIVISOR - (depositFee))/(BASIS_POINTS_DIVISOR);
            uint256 feeAmount = _amountIn-(afterFeeAmount);
            feeReserves[collateralToken] = feeReserves[collateralToken]+(feeAmount);
            return afterFeeAmount;
        }

        return _amountIn;
    }
}
          

src/contracts/core/interfaces/IOrderManager.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;
import "./../../libraries/utils/Structs.sol";

interface IOrderManager {
    function increasePositionRequestKeysStart() external view returns (uint256);

    function decreasePositionRequestKeysStart() external view returns (uint256);

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

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

    function executeOrder(address, uint256, address payable) external;

    function setOrderKeeper(address _account, bool _isActive) external;

    function setPriceFeed(address _priceFeed) external;

    function executeMultipleOrders(
        address[] calldata accountAddresses,
        uint[] calldata orderIndices,
        address payable _feeReceiver
    ) external;

    function liquidateMultiplePositions(
        bytes32[] calldata keys,
        address payable _feeReceiver
    ) external;

    function getIncreasePositionCount() external view returns (uint);

    function getDecreasePositionCount() external view returns (uint);
}
          

src/contracts/core/interfaces/IPriceFeed.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface IPriceFeed {
    function getMaxPriceOfToken(address _token) external view returns (uint256);
    function getMinPriceOfToken(address _token) external view returns (uint256);
    function getPriceOfToken(address _token) external view returns (uint256);
}
          

src/contracts/core/interfaces/ITimeLock.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface ITimelock {
    function setAdmin(address _admin) external;
    function signalSetGov(address _target, address _gov) external;
}
          

src/contracts/core/interfaces/IUtils.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

interface IUtils {
    function validateIncreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external view;
    function validateDecreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong, address _receiver) external view;
    function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise,  uint256 _markPrice) external returns (uint256, int256);
    function getEntryBorrowingRate(address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256);
    function getEntryFundingRate(address _collateralToken, address _indexToken, bool _isLong) external view returns (int256);
    function getPositionFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _sizeDelta) external view returns (uint256);
    function getBorrowingFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _size, uint256 _entryBorrowingRate) external view returns (uint256);
    function getBuyUsdlFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
    function getSellUsdlFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
    function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, bool _increment) external view returns (uint256);
    function getDelta(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        uint256 _nextPrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) external view returns (bool, uint256);
    function getNextGlobalAveragePrice(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _nextPrice,
        uint256 _sizeDelta,
        bool _isLong,
        bool _isIncrease
    ) external view returns (uint256);
    function getNextAveragePrice(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _nextPrice,
        uint256 _sizeDelta,
        uint256 _lastIncreasedTime
    ) external view returns (uint256);
    function adjustForDecimals(
        uint256 _amount,
        address _tokenDiv,
        address _tokenMul
    ) external view returns (uint256);
    function getGlobalPositionDelta(address _token, uint size, bool _isLong) external view returns (bool, uint256);
    function getAum(bool maximise) external view returns (uint256);
    function getAumInUsdl(
        bool maximise
    ) external view returns (uint256);
    function validatePosition(
        uint256 _size,
        uint256 _collateral
    ) external view;

    function getNextBorrowingRate(address _indexToken, bool _isLong) external view returns(uint);
    function getMinPrice(address _token) external view returns (uint256);
    function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);
    function getMaxPrice(address _token) external view returns (uint256);
    function usdToTokenMin(address _token, uint256 _usdAmount) external view returns (uint256);
    function usdToTokenMax(address _token, uint256 _usdAmount) external view returns (uint256);
    function updateCumulativeBorrowingRate(address _indexToken) external view returns(uint256 borrowingTime, uint256 borrowingRateForLongs, uint256 borrowingRateForShorts);
    function updateCumulativeFundingRate(address _indexToken, uint256 lastFundingTime) external returns(uint lastFundingUpdateTime, int256 fundingRateForLong, int256 fundingRateForShort);
    function getRedemptionAmount(address _token, uint256 _usdlAmount) external view  returns (uint256);
    function collectMarginFees(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta,
        uint256 _size,
        uint256 _entryBorrowingRate,
        int256 _entryFundingRate
    ) external returns (int256 feeUsd);
    function getTPPrice(uint256 sizeDelta, bool isLong, uint256 markPrice, uint256 _maxTPAmount, address collateralToken) external returns(uint256);
    function calcLiquidationFee(uint256 size, address indexToken) external returns(uint);
    function setPriceFeed(address _pricefeed) external;
    function getOI(address _token, bool _isLong) view external returns(uint);
    function getLPAmountInUSD() external view returns(uint lpAmountInUSD);
    function getTotalOI() view external returns(uint totalOI);
    function maintanenceMargin(address token) external view returns(uint);
    function tokenPremiumPositionFee(address token) external view returns(int);

}
          

src/contracts/core/interfaces/IVault.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "./IUtils.sol";
import "./../../libraries/utils/Structs.sol";

interface IVault {
    struct FundingFeeData {
        uint256 fundingRateFactor;
        uint256 fundingInterval;
        uint256 fundingExponent;
    }
    struct BorrowingFeeData {
        uint256 borrowingRateFactor;
        uint256 borrowingInterval;
        uint256 borrowingExponent;
    }

    function isInitialized() external view returns (bool);

    function setUtils(address _utils) external;

    function usdl() external view returns (address);

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

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

    function gov() external view returns (address);

    function ceaseTradingActivity() external view returns (bool);

    function ceaseLPActivity() external view returns (bool);

    function minProfitTime() external view returns (uint256);

    function hasDynamicFees() external view returns (bool);

    function inManagerMode() external view returns (bool);

    function inPrivateLiquidationMode() external view returns (bool);

    function maxGasPrice() external view returns (uint256);

    function isLiquidator(address _account) external view returns (bool);

    function isManager(address _account) external view returns (bool);

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

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

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

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

    function setMaxLeverage(uint256 _maxLeverage, address _token) external;

    function setInManagerMode(bool _inManagerMode) external;

    function setManager(address _manager, bool _isManager) external;

    function setMaxGasPrice(uint256 _maxGasPrice) external;

    function setMaxGlobalShortSize(address _token, uint256 _amount) external;

    function setMaxGlobalLongSize(address _token, uint256 _amount) external;

    function setInPrivateLiquidationMode(
        bool _inPrivateLiquidationMode
    ) external;

    function setLiquidator(address _liquidator, bool _isActive) external;

    function setBorrowingRate(
        address token,
        uint256 _borrowingInterval,
        uint256 _borrowingRateFactor,
        uint256 borrowingExponent
    ) external;

    function setFundingRate(
        address token,
        uint256 _fundingInterval,
        uint256 _fundingRateFactor,
        uint256 fundingExponent
    ) external;

    function setFees(
        uint256 _mintBurnFeeBasisPoints,
        uint256 _marginFeeBasisPoints,
        uint256 _liquidationFeeUsd,
        uint256 liquidationFactor,
        uint256 _minProfitTime,
        bool _hasDynamicFees
    ) external;

    function setTokenConfig(
        address _token,
        uint256 _tokenDecimals,
        uint256 _minProfitBps,
        bool _isStable,
        bool _canBeCollateralToken,
        bool _canBeIndexToken,
        uint _maxLeverage
    ) external;

    function setCeaseLPActivity(bool _cease) external;

    function setCeaseTradingActivity(bool _cease) external;

    function setPriceFeed(address _priceFeed) external;

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

    function setGov(address _gov) external;

    function directPoolDeposit(address _token) external;

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

    function sellUSDL(
        address _token,
        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 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external returns (uint256);

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

    function liquidatePosition(bytes32 key, address feeReceiver) external;

    function priceFeed() external view returns (address);

    function fundingRateFactor(
        address
    ) external view returns (uint256, uint256, uint256);

    function borrowingRateFactor(
        address
    ) external view returns (uint256, uint256, uint256);

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

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

    function cumulativeFundingRatesForLongs(
        address _token
    ) external view returns (int);

    function cumulativeFundingRatesForShorts(
        address _token
    ) external view returns (int);

    function liquidationFeeUsd() external view returns (uint256);

    function liquidationFactor() external view returns (uint256);

    function mintBurnFeeBasisPoints() external view returns (uint256);

    function marginFeeBasisPoints() external view returns (uint256);

    function allWhitelistedTokensLength() external view returns (uint256);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function setGlobalLongSizesLimitBps(address token, uint amount) external;

    function setGlobalShortSizesLimitBps(address token, uint amount) external;

    function setPoolSafetyFactorInBps(uint _poolSafetyFactorInBps) external;

    function getPosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    ) external view returns (StructsUtils.Position memory);

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

    function globalLongSizesLimitBps(
        address _token
    ) external view returns (uint256);
}
          

src/contracts/libraries/token/Address.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.19;

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

src/contracts/libraries/token/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.19;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
    function decimals() external view returns (uint8);
}
          

src/contracts/libraries/token/IERC20Permit.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.19;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

src/contracts/libraries/token/SafeERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.19;

import "./IERC20.sol";
import "./IERC20Permit.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 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)+(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)-(value);
        _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");
        }
    }
}
          

src/contracts/libraries/utils/EnumerableSet.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.19;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 value => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}
          

src/contracts/libraries/utils/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.19;

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

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    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 making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        if (_status == _ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

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

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}
          

src/contracts/libraries/utils/Structs.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

library StructsUtils {
    struct IncreasePositionRequest {
        address account;
        address _collateralToken;
        address indexToken;
        uint256 amountIn;
        uint256 sizeDelta;
        bool isLong;
        uint256 acceptablePrice;
        uint256 executionFee;
        uint256 blockNumber;
        uint256 blockTime;
    }
    struct DecreasePositionRequest {
        address account;
        address _collateralToken;
        address indexToken;
        uint256 sizeDelta;
        bool isLong;
        address receiver;
        uint256 acceptablePrice;
        uint256 executionFee;
        uint256 blockNumber;
        uint256 blockTime;
    }
    struct Order {
        address account;
        address collateralToken;
        address indexToken;
        uint256 collateralDelta;
        uint256 sizeDelta;
        uint256 triggerPrice;
        uint256 executionFee;
        bool isLong;
        bool triggerAboveThreshold;
        bool isIncreaseOrder;
        bool isMaxOrder;
        uint256 orderIndex;
        uint256 creationTime;
    }
    struct Position {
        address account;
        address collateralToken;
        address indexToken;
        bool isLong;
        uint256 size;
        uint256 collateral;
        uint256 averagePrice;
        uint256 entryBorrowingRate;
        int256 entryFundingRate;
        int256 realisedPnl;
        uint256 lastIncreasedTime;
    }

    struct MintLLPRequest {
        address account;
        uint256 amount;
        address collateralToken;
        uint256 executionFee;
        uint256 minUsdl;
        uint256 minLLP;
    }

    struct BurnLLPRequest {
        address account;
        uint256 amount;
        address collateralToken;
        uint256 minOut;
        address receiver;
        uint256 executionFee;
    }

    struct LiquidatorCacheReturn {
        IndexTokenDetails[] indexTokenDetailsArray;
        VaultDetails vaultDetails;
    }

    struct IndexTokenDetails {
        address indexToken;
        uint256 minProfitBasisPoints;
        uint256 maintanenceMargin;
        CumulativeBorrowingRate cumulativeBorrowingRate;
        CumulativeFundingRate cumulativeFundingRate;
    }

    struct CumulativeBorrowingRate {
        uint256 borrowingTime;
        uint256 currentBorrowingRateLongs;
        uint256 currentBorrowingRateShorts;
    }

    struct CumulativeFundingRate {
        uint lastFundingTime;
        int currentFundingRateLongs;
        int currentFundingRateShorts;
    }

    struct VaultDetails {
        uint256 minProfitTime;
        uint256 liquidationFactor;
        uint256 liquidationFeeUsd;
        uint256 marginFeeBasisPoints;
    }

    struct FECacheReturn {
        IndexTokenDetailsFE[] indexTokenDetailsArray;
        PoolDetailsFE poolDetails;
    }

    struct IndexTokenDetailsFE {
        address indexToken;
        uint borrowingRateLong;
        uint borrowingRateShort;
        int256 fundingRateLong;
        int256 fundingRateShort;
        uint longOpenInterest;
        uint shortOpenInterest;
        uint256 globalLongSizesLimitBps;
        uint256 globalShortSizesLimitBps;
    }

    struct PoolDetailsFE {
        uint256 totalSupply;
        uint256 totalStaked;
        uint256 poolValue;
        uint256 poolAmounts;
    }
}
          

Compiler Settings

{"viaIR":false,"remappings":["pyth-sdk-solidity/=lib/pyth-sdk-solidity/","ds-test/=lib/forge-std/lib/ds-test/src/","forge-std/=lib/forge-std/src/"],"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_vault","internalType":"address"},{"type":"address","name":"_utils","internalType":"address"},{"type":"address","name":"_pricefeed","internalType":"address"},{"type":"uint256","name":"_minExecutionFeeMarketOrder","internalType":"uint256"},{"type":"uint256","name":"_minExecutionFeeLimitOrder","internalType":"uint256"},{"type":"uint256","name":"_depositFee","internalType":"uint256"},{"type":"uint256","name":"_maxProfitMultiplier","internalType":"uint256"},{"type":"uint256","name":"_minPurchaseUSDAmountLimitOrder","internalType":"uint256"},{"type":"uint256","name":"_minPurchaseUSDAmountMarketOrder","internalType":"uint256"}]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"event","name":"CancelDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","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":"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":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","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":"CancelOrder","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"orderIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool","indexed":false},{"type":"bool","name":"isIncreaseOrder","internalType":"bool","indexed":true},{"type":"bool","name":"isMaxOrder","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"CreateDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","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":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"uint256","name":"queueIndex","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":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","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":"queueIndex","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":"CreateOrder","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"orderIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool","indexed":false},{"type":"bool","name":"isIncreaseOrder","internalType":"bool","indexed":true},{"type":"bool","name":"isMaxOrder","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"ExecuteDecreasePosition","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","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":"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":"_collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"amountIn","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":"ExecuteOrder","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"orderIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"executionPrice","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool","indexed":false},{"type":"bool","name":"isIncreaseOrder","internalType":"bool","indexed":true}],"anonymous":false},{"type":"event","name":"LeverageDecreased","inputs":[{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"prevLeverage","internalType":"uint256","indexed":false},{"type":"uint256","name":"nextLeverage","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetDelayValues","inputs":[{"type":"uint256","name":"minBlockDelayKeeper","internalType":"uint256","indexed":false},{"type":"uint256","name":"minTimeDelayPublic","internalType":"uint256","indexed":false},{"type":"uint256","name":"maxTimeDelay","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetLiquidator","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isActive","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"SetOrderKeeper","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"isActive","internalType":"bool","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":"UpdateOrder","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"collateralToken","internalType":"address","indexed":false},{"type":"address","name":"indexToken","internalType":"address","indexed":false},{"type":"uint256","name":"orderIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"collateralDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"sizeDelta","internalType":"uint256","indexed":false},{"type":"uint256","name":"triggerPrice","internalType":"uint256","indexed":false},{"type":"bool","name":"isLong","internalType":"bool","indexed":false},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool","indexed":false},{"type":"bool","name":"isIncreaseOrder","internalType":"bool","indexed":true},{"type":"bool","name":"isMaxOrder","internalType":"bool","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":"address","name":"","internalType":"address"}],"name":"admin","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":"nonpayable","outputs":[],"name":"cancelOrder","inputs":[{"type":"uint256","name":"_orderIndex","internalType":"uint256"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"createDecreasePosition","inputs":[{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"address","name":"_receiver","internalType":"address"},{"type":"uint256","name":"_acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"_executionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"createIncreasePosition","inputs":[{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"uint256","name":"_amountIn","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"bool","name":"_isLong","internalType":"bool"},{"type":"uint256","name":"_acceptablePrice","internalType":"uint256"},{"type":"uint256","name":"takeProfitPrice","internalType":"uint256"},{"type":"uint256","name":"stopLossPrice","internalType":"uint256"},{"type":"uint256","name":"_executionFee","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createOrders","inputs":[{"type":"uint256","name":"collateralDelta","internalType":"uint256"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"sizeDelta","internalType":"uint256"},{"type":"address","name":"collateralToken","internalType":"address"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"uint256","name":"_executionFee","internalType":"uint256"},{"type":"uint256","name":"limitPrice","internalType":"uint256"},{"type":"uint256","name":"tpPrice","internalType":"uint256"},{"type":"uint256","name":"slPrice","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":"_collateralToken","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"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":"executionFee","internalType":"uint256"},{"type":"uint256","name":"blockNumber","internalType":"uint256"},{"type":"uint256","name":"blockTime","internalType":"uint256"}],"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":"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":[{"type":"uint256","name":"","internalType":"uint256"}],"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":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"executeIncreasePositions","inputs":[{"type":"uint256","name":"_endIndex","internalType":"uint256"},{"type":"address","name":"_executionFeeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeMultipleOrders","inputs":[{"type":"address[]","name":"accountAddresses","internalType":"address[]"},{"type":"uint256[]","name":"orderIndices","internalType":"uint256[]"},{"type":"address","name":"_feeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeOrder","inputs":[{"type":"address","name":"_address","internalType":"address"},{"type":"uint256","name":"_orderIndex","internalType":"uint256"},{"type":"address","name":"_feeReceiver","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":"tuple[]","name":"","internalType":"struct StructsUtils.Order[]","components":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"collateralToken","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"collateralDelta","internalType":"uint256"},{"type":"uint256","name":"sizeDelta","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool"},{"type":"bool","name":"isIncreaseOrder","internalType":"bool"},{"type":"bool","name":"isMaxOrder","internalType":"bool"},{"type":"uint256","name":"orderIndex","internalType":"uint256"},{"type":"uint256","name":"creationTime","internalType":"uint256"}]}],"name":"getAllOrders","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDecreasePositionCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getIncreasePositionCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct StructsUtils.IncreasePositionRequest","components":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"amountIn","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"}]}],"name":"getIncreasePositionRequestFromIndex","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getOrderKey","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"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":"_collateralToken","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"amountIn","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"}],"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":"isLiquidator","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOrderKeeper","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":"nonpayable","outputs":[],"name":"liquidateMultiplePositions","inputs":[{"type":"bytes32[]","name":"keys","internalType":"bytes32[]"},{"type":"address","name":"_feeReceiver","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxProfitMultiplier","inputs":[]},{"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":"minExecutionFeeDecreaseLimitOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minExecutionFeeDecreaseMarketOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minExecutionFeeIncreaseLimitOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minExecutionFeeIncreaseMarketOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minPurchaseUSDAmountLimitOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minPurchaseUSDAmountMarketOrder","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"minTimeDelayPublic","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"collateralToken","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"uint256","name":"collateralDelta","internalType":"uint256"},{"type":"uint256","name":"sizeDelta","internalType":"uint256"},{"type":"uint256","name":"triggerPrice","internalType":"uint256"},{"type":"uint256","name":"executionFee","internalType":"uint256"},{"type":"bool","name":"isLong","internalType":"bool"},{"type":"bool","name":"triggerAboveThreshold","internalType":"bool"},{"type":"bool","name":"isIncreaseOrder","internalType":"bool"},{"type":"bool","name":"isMaxOrder","internalType":"bool"},{"type":"uint256","name":"orderIndex","internalType":"uint256"},{"type":"uint256","name":"creationTime","internalType":"uint256"}],"name":"orders","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ordersIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pricefeed","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"retrieveStuckFunds","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAdmin","inputs":[{"type":"address","name":"_admin","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDelayValues","inputs":[{"type":"uint256","name":"_minBlockDelayKeeper","internalType":"uint256"},{"type":"uint256","name":"_minTimeDelayPublic","internalType":"uint256"},{"type":"uint256","name":"_maxTimeDelay","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDepositFee","inputs":[{"type":"uint256","name":"_fee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setLiquidator","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"bool","name":"_isActive","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxTPMultiplier","inputs":[{"type":"uint256","name":"_maxProfitMultiplier","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinExecutionFeeLimitOrder","inputs":[{"type":"uint256","name":"_minExecutionFeeIncreaseLimitOrder","internalType":"uint256"},{"type":"uint256","name":"_minExecutionFeeDecreaseLimitOrder","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinExecutionFeeMarketOrder","inputs":[{"type":"uint256","name":"_minExecutionFeeIncreaseMarketOrder","internalType":"uint256"},{"type":"uint256","name":"_minExecutionFeeDecreaseMarketOrder","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMinPurchaseAmount","inputs":[{"type":"uint256","name":"_marketOrder","internalType":"uint256"},{"type":"uint256","name":"_limitOrder","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOrderKeeper","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"bool","name":"_isActive","internalType":"bool"}]},{"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":"setPriceFeed","inputs":[{"type":"address","name":"_priceFeed","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setUtils","inputs":[{"type":"address","name":"_utils","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVault","inputs":[{"type":"address","name":"_vault","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateOrder","inputs":[{"type":"uint256","name":"_orderIndex","internalType":"uint256"},{"type":"uint256","name":"_sizeDelta","internalType":"uint256"},{"type":"uint256","name":"_newCollateralAmount","internalType":"uint256"},{"type":"uint256","name":"_triggerPrice","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"utils","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"}],"name":"validatePositionOrderPrice","inputs":[{"type":"bool","name":"_triggerAboveThreshold","internalType":"bool"},{"type":"uint256","name":"_triggerPrice","internalType":"uint256"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"bool","name":"","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vault","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFees","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_receiver","internalType":"address"}]}]
              

Contract Creation Code

0x608060405260646004553480156200001657600080fd5b5060405162005da238038062005da28339810160408190526200003991620000d4565b600180546001600160a01b03199081166001600160a01b039b8c161782556002805482169a8c169a909a17909955600380548a1698909a169790971790985560008054339816979097179096556006919091556007939093556008829055600991909155600a819055600b55601e55601f9190915560205562000159565b80516001600160a01b0381168114620000cf57600080fd5b919050565b60008060008060008060008060006101208a8c031215620000f457600080fd5b620000ff8a620000b7565b98506200010f60208b01620000b7565b97506200011f60408b01620000b7565b965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b615c3980620001696000396000f3fe6080604052600436106103ce5760003560e01c80636410659a116101fd578063a5a89c0911610118578063ddef7e85116100ab578063f3883d8b1161007a578063f3883d8b14610cef578063f851a44014610d0f578063fa44457714610d2f578063faf990f314610d5c578063fbfa77cf14610e3757600080fd5b8063ddef7e8514610c7a578063e4d8f76814610c9a578063eea3f2f614610cba578063f255527814610ccf57600080fd5b8063c66a29f0116100e7578063c66a29f014610c0e578063cb0269c914610c2e578063cefdb8b614610c44578063dd53831614610c6457600080fd5b8063a5a89c0914610b9b578063a915e53b14610bae578063ad988fea14610bc1578063ae5efa2b14610bee57600080fd5b80638d60b392116101905780639a2081001161015f5780639a20810014610a395780639b57862014610a595780639c3e86ca14610a6f5780639c3f1e9014610a8457600080fd5b80638d60b392146109cd57806394ac7ec0146109ed57806398d1e03a14610a03578063990269e514610a1957600080fd5b8063704b6c02116101cc578063704b6c021461094b578063724e78da1461096b5780637323a7d31461098b5780637bea0d1c146109ab57600080fd5b80636410659a146108d557806367a52793146108f55780636817031b1461090b578063699535011461092b57600080fd5b80633833f5f5116102ed578063529a356f116102805780635b4c58df1161024f5780635b4c58df146108265780635b8d97751461085b57806360a362e214610888578063633451de146108a857600080fd5b8063529a356f146107885780635841fcaa146107b8578063590f2113146107ce5780635a29638d1461080657600080fd5b806343a28ba9116102bc57806343a28ba9146107125780634440423e146107285780634453a37414610748578063490ae2101461076857600080fd5b80633833f5f5146106965780633a2a80c7146106c65780633b0befca146106dc5780634067b132146106f257600080fd5b8063225fc9fd116103655780633422ead1116103345780633422ead11461061d578063347c91aa1461063d57806335d4a1031461065057806336eba48a1461066657600080fd5b8063225fc9fd146105a75780632327361d146105c757806327b42c0f146105e75780632953cb7a1461060757600080fd5b80631bca8cf0116103a15780631bca8cf0146104625780631ce9cb8f146104785780631e261538146104a55780631f285106146104c757600080fd5b806304225954146103d35780630c40f430146104065780630d4d003d1461041c578063126082cf1461044c575b600080fd5b3480156103df57600080fd5b506103f36103ee366004615122565b610e57565b6040519081526020015b60405180910390f35b34801561041257600080fd5b506103f360085481565b34801561042857600080fd5b5061043c610437366004615153565b610e78565b60405190151581526020016103fd565b34801561045857600080fd5b506103f361271081565b34801561046e57600080fd5b506103f360175481565b34801561048457600080fd5b506103f3610493366004615183565b60056020526000908152604090205481565b3480156104b157600080fd5b506104c56104c03660046151ae565b61112a565b005b3480156104d357600080fd5b506105426104e2366004615122565b6010602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b03978816989688169795861696949560ff8516956101009095041693908a565b604080516001600160a01b039b8c168152998b1660208b0152978a169789019790975260608801959095529215156080870152951660a085015260c084019490945260e0830193909352610100820192909252610120810191909152610140016103fd565b3480156105b357600080fd5b5061043c6105c2366004615153565b6111b4565b3480156105d357600080fd5b506104c56105e23660046151dc565b61145b565b3480156105f357600080fd5b5061043c610602366004615153565b611546565b34801561061357600080fd5b506103f360095481565b34801561062957600080fd5b506104c56106383660046151ae565b6118e3565b6103f361064b366004615208565b611965565b34801561065c57600080fd5b506103f360205481565b34801561067257600080fd5b5061043c610681366004615183565b60126020526000908152604090205460ff1681565b3480156106a257600080fd5b5061043c6106b1366004615183565b601c6020526000908152604090205460ff1681565b3480156106d257600080fd5b506103f360145481565b3480156106e857600080fd5b506103f3601e5481565b3480156106fe57600080fd5b506104c561070d366004615282565b611aae565b34801561071e57600080fd5b506103f3601f5481565b34801561073457600080fd5b506104c56107433660046152ae565b611b2e565b34801561075457600080fd5b506104c56107633660046151ae565b611b63565b34801561077457600080fd5b506104c5610783366004615122565b611be5565b34801561079457600080fd5b5061043c6107a3366004615183565b601d6020526000908152604090205460ff1681565b3480156107c457600080fd5b506103f360135481565b3480156107da57600080fd5b506003546107ee906001600160a01b031681565b6040516001600160a01b0390911681526020016103fd565b34801561081257600080fd5b506002546107ee906001600160a01b031681565b34801561083257600080fd5b506108466108413660046152d0565b611c14565b604080519283529015156020830152016103fd565b34801561086757600080fd5b506103f3610876366004615183565b601b6020526000908152604090205481565b34801561089457600080fd5b5061043c6108a3366004615153565b611ce2565b3480156108b457600080fd5b506103f36108c3366004615183565b600c6020526000908152604090205481565b3480156108e157600080fd5b506104c56108f0366004615323565b611f1c565b34801561090157600080fd5b506103f360065481565b34801561091757600080fd5b506104c5610926366004615183565b612549565b34801561093757600080fd5b506104c5610946366004615183565b612595565b34801561095757600080fd5b506104c5610966366004615183565b6125e1565b34801561097757600080fd5b506104c5610986366004615183565b61262d565b34801561099757600080fd5b506104c56109a6366004615153565b612679565b3480156109b757600080fd5b506109c06127e9565b6040516103fd9190615365565b3480156109d957600080fd5b506104c56109e83660046152ae565b6129c6565b3480156109f957600080fd5b506103f3600b5481565b348015610a0f57600080fd5b506103f360045481565b348015610a2557600080fd5b506104c5610a34366004615122565b6129fb565b348015610a4557600080fd5b506103f3610a54366004615153565b612a2a565b348015610a6557600080fd5b506103f360165481565b348015610a7b57600080fd5b50600e546103f3565b348015610a9057600080fd5b50610b20610a9f366004615122565b60186020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b03988916999789169890961696949593949293919260ff808316936101008404821693620100008104831693630100000090910490921691908d565b604080516001600160a01b039e8f1681529c8e1660208e01529a909c16998b019990995260608a0197909752608089019590955260a088019390935260c0870191909152151560e08601521515610100850152151561012084015215156101408301526101608201526101808101919091526101a0016103fd565b6104c5610ba936600461543f565b612be4565b6103f3610bbc3660046154c1565b612ebb565b348015610bcd57600080fd5b50610be1610bdc366004615122565b61317b565b6040516103fd9190615519565b348015610bfa57600080fd5b506104c5610c09366004615607565b61330a565b348015610c1a57600080fd5b506103f3610c293660046151dc565b61340a565b348015610c3a57600080fd5b506103f360155481565b348015610c5057600080fd5b506104c5610c5f36600461568b565b613451565b348015610c7057600080fd5b506103f3600a5481565b348015610c8657600080fd5b506104c5610c953660046152ae565b6135e5565b348015610ca657600080fd5b506104c5610cb53660046156bd565b61361a565b348015610cc657600080fd5b506011546103f3565b348015610cdb57600080fd5b506104c5610cea366004615709565b6136f4565b348015610cfb57600080fd5b506103f3610d0a366004615153565b6137b0565b348015610d1b57600080fd5b506000546107ee906001600160a01b031681565b348015610d3b57600080fd5b506103f3610d4a366004615183565b600f6020526000908152604090205481565b348015610d6857600080fd5b50610dda610d77366004615122565b600d6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b039889169997891698909616969495939460ff90931693919290918a565b604080516001600160a01b039b8c168152998b1660208b0152979099169688019690965260608701949094526080860192909252151560a085015260c084015260e0830152610100820152610120810191909152610140016103fd565b348015610e4357600080fd5b506001546107ee906001600160a01b031681565b600e8181548110610e6757600080fd5b600091825260209091200154905081565b6000610e8261396a565b60008381526010602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015481169482019490945260038201546060820152600482015460ff8116151560808301526101009081900490941660a0820152600582015460c0820152600682015460e082015260078201549381019390935260080154610120830152610f2a57600191505061111a565b610f438161010001518261012001518360000151613994565b610f5157600091505061111a565b600084815260106020908152604080832080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018490556004810180546001600160a81b0319169055600581018490556006810184905560078101849055600801839055835191840151908401516060850151608086015160c0870151610fe495949392919030906139f0565b60a08301516020840151919250611005916001600160a01b03169083613ba3565b60e08201516040516000916001600160a01b038716918381818185875af1925050503d8060008114611053576040519150601f19603f3d011682016040523d82523d6000602084013e611058565b606091505b50509050806110825760405162461bcd60e51b815260040161107990615737565b60405180910390fd5b82600001516001600160a01b03167fbece414bdfb172bf1b798de2a8ecc3c86ec25ad7011ee97f4e3549715137b5ef84602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151436110e5919061576b565b6101208d01516110f5904261576b565b60405161110a9998979695949392919061577e565b60405180910390a2600193505050505b6111246001600755565b92915050565b6000546001600160a01b031633146111545760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000818152601c6020908152604091829020805460ff191685151590811790915591519182527f1d5bc0255b943d6a5b5279e8a55d74d620baccbceecb25e87a3558f14c4c118e91015b60405180910390a25050565b60006111be61396a565b6000838152600d602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460ff16151560a0840152600681015460c0840152600781015460e084015260088101546101008401526009015461012083015261125e57600191505061111a565b6112778161010001518261012001518360000151613c06565b61128557600091505061111a565b6000848152600d60209081526040822080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018390556004810183905560058101805460ff19169055600681018390556007810183905560088101839055600901919091558151606083015191830151611311926001600160a01b039091169190613ba3565b60e08101516040516000916001600160a01b038616918381818185875af1925050503d806000811461135f576040519150601f19603f3d011682016040523d82523d6000602084013e611364565b606091505b50509050806113855760405162461bcd60e51b815260040161107990615737565b81600001516001600160a01b03167fb46dc78d7a64b7dd9e215a1a5955b8e522c417f8260520d97a2ce9a73c72bd1283602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151436113e8919061576b565b6101208c01516113f8904261576b565b604080516001600160a01b039a8b1681529990981660208a0152968801959095526060870193909352901515608086015260a085015260c084015260e0830152610100820152610120015b60405180910390a26001925050506111246001600755565b6000546001600160a01b031633146114855760405162461bcd60e51b8152600401611079906157d4565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156114c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ed91906157f4565b8111156115285760405162461bcd60e51b815260206004820152600960248201526813d34e985b5bdd5b9d60ba1b6044820152606401611079565b600054611542906001600160a01b03848116911683613ba3565b5050565b600061155061396a565b6000838152600d602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460ff16151560a0840152600681015460c0840152600781015460e08401526008810154610100840152600901546101208301526115f057600191505061111a565b6116098161010001518261012001518360000151613994565b61161757600091505061111a565b6000848152600d6020908152604080832080546001600160a01b031990811682556001808301805483169055600283018054909216909155600382018590556004820185905560058201805460ff19169055600682018590556007820185905560088201859055600990910193909355915483519184015160608501519385015160a086015160808701516116d7966001600160a01b03909516956116c29590949390929091613c13565b60208401516001600160a01b03169190613ba3565b6116fd81600001518260200151836040015184608001518560a001518660c00151613cb7565b60e08101516040516000916001600160a01b038616918381818185875af1925050503d806000811461174b576040519150601f19603f3d011682016040523d82523d6000602084013e611750565b606091505b50509050806117715760405162461bcd60e51b815260040161107990615737565b608082015115611880576000600260009054906101000a90046001600160a01b03166001600160a01b0316635dc271d684608001518560a001518660c00151601e5488606001516117c2919061580d565b60208901516040516001600160e01b031960e088901b16815260048101959095529215156024850152604484019190915260648301526001600160a01b0316608482015260a4016020604051808303816000875af1158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c91906157f4565b905061187e836000015160008560200151866040015187608001518860a00151878a60a00151600b5460006001613e73565b505b81600001516001600160a01b03167f02ca30b520a08cead06dc4eb7847b9df09adf21e5e07dd7d2d8c32381fecb75283602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151436113e8919061576b565b6000546001600160a01b0316331461190d5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b038216600081815260126020908152604091829020805460ff191685151590811790915591519182527ffbabc02389290a451c6e600d05bf9887b99bfad39d8e1237e4e3df042e4941fe91016111a8565b600061196f61396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e69190615834565b15611a035760405162461bcd60e51b815260040161107990615851565b600954821015611a255760405162461bcd60e51b815260040161107990615737565b348214611a445760405162461bcd60e51b81526004016110799061586f565b611a51338989888a6140de565b611a875760405162461bcd60e51b81526020600482015260076024820152664f4d3a73697a6560c81b6044820152606401611079565b611a973389898989898989614190565b9050611aa36001600755565b979650505050505050565b6000546001600160a01b03163314611ad85760405162461bcd60e51b8152600401611079906157d4565b60138390556014829055601581905560408051848152602081018490529081018290527fb98e759701eaca2e60c25e91109003c1c7442ef731b5d569037063005da8254d906060015b60405180910390a1505050565b6000546001600160a01b03163314611b585760405162461bcd60e51b8152600401611079906157d4565b600a91909155600b55565b6000546001600160a01b03163314611b8d5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000818152601d6020908152604091829020805460ff191685151590811790915591519182527f8c0d56805c3b43d441481229dc64bee168253ffe4305f37ab7cfe63b1c4268c691016111a8565b6000546001600160a01b03163314611c0f5760405162461bcd60e51b8152600401611079906157d4565b600655565b6003546040516311b5088f60e31b81526001600160a01b0384811660048301526000928392839290911690638da8447890602401602060405180830381865afa158015611c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8991906157f4565b9050600087611c9a57868210611c9e565b8682115b905080611cd55760405162461bcd60e51b815260206004820152600560248201526427a69d383960d91b6044820152606401611079565b9097909650945050505050565b6000611cec61396a565b60008381526010602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015481169482019490945260038201546060820152600482015460ff8116151560808301526101009081900490941660a0820152600582015460c0820152600682015460e082015260078201549381019390935260080154610120830152611d9457600191505061111a565b611dad8161010001518261012001518360000151613c06565b611dbb57600091505061111a565b60008481526010602052604080822080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018390556004810180546001600160a81b031916905560058101839055600681018390556007810183905560080182905560e083015190516001600160a01b03861691908381818185875af1925050503d8060008114611e6e576040519150601f19603f3d011682016040523d82523d6000602084013e611e73565b606091505b5050905080611e945760405162461bcd60e51b815260040161107990615737565b81600001516001600160a01b03167fd2c665be6c7dd696827595026252b33f769220c8a4d2813d855c5d393afc158c83602001518460400151856060015186608001518760a001518860c001518960e001518a610100015143611ef7919061576b565b6101208c0151611f07904261576b565b6040516114439998979695949392919061577e565b611f2461396a565b336000908152601c602052604090205460ff16611f535760405162461bcd60e51b81526004016110799061588e565b6000611f5f848461340a565b60008181526018602090815260409182902082516101a08101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460a0840152600681015460c0840152600781015460ff808216151560e08601526101008083048216151590860152620100008204811615156101208601526301000000909104161515610140840152600881015461016084015260090154610180830152919250906120425760405162461bcd60e51b8152600401611079906158ae565b60006120618261010001518360a0015184604001518560e00151611c14565b509050816101200151156122385760015460608301516020840151612094926001600160a01b0391821692911690613ba3565b60015482516020840151604080860151608087015160e088015192516348d91abf60e01b81526001600160a01b039586166004820152938516602485015290841660448401526064830152151560848201529116906348d91abf9060a401600060405180830381600087803b15801561210c57600080fd5b505af1158015612120573d6000803e3d6000fd5b50505050608082015115612233576000600260009054906101000a90046001600160a01b03166001600160a01b0316635dc271d684608001518560e001518660a00151601e548860600151612175919061580d565b60208901516040516001600160e01b031960e088901b16815260048101959095529215156024850152604484019190915260648301526001600160a01b0316608482015260a4016020604051808303816000875af11580156121db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ff91906157f4565b9050612231836000015160008560200151866040015187608001518860e00151878a60e00151600b5460006001613e73565b505b61232b565b600061225b8360000151846020015185604001518660e0015187608001516140de565b9050806122775761226e848785886142ee565b5050505061253a565b60015483516020850151604080870151608088015160e08901519251633cae4d0160e11b81526000966001600160a01b03169563795c9a02956122c79591949093909290919030906004016158cf565b6020604051808303816000875af11580156122e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230a91906157f4565b84516020860151919250612328916001600160a01b03169083613ba3565b50505b600083815260186020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101829055600581018290556006810182905560078101805463ffffffff19169055600881018290556009015561239f601984614512565b5060c08201516040516000916001600160a01b038716918381818185875af1925050503d80600081146123ee576040519150601f19603f3d011682016040523d82523d6000602084013e6123f3565b606091505b50509050806124145760405162461bcd60e51b815260040161107990615737565b826101200151151583600001516001600160a01b03167ff24fdd74c4b1144dd9f57bc5cc659cf1cfc0a71cff35b366ff486c212510d9bb856020015186604001518a886060015189608001518a60a001518b60c001518b8d60e001518e61010001516040516124dc9a999897969594939291906001600160a01b039a8b16815298909916602089015260408801969096526060870194909452608086019290925260a085015260c084015260e083015215156101008201529015156101208201526101400190565b60405180910390a38251602084015160408086015161014087015191516000946001600160a01b031693600080516020615be48339815191529361252d9391928d9188918291829182918291615909565b60405180910390a3505050505b6125446001600755565b505050565b6000546001600160a01b031633146125735760405162461bcd60e51b8152600401611079906157d4565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146125bf5760405162461bcd60e51b8152600401611079906157d4565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461260b5760405162461bcd60e51b8152600401611079906157d4565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146126575760405162461bcd60e51b8152600401611079906157d4565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b61268161396a565b600061268d828461340a565b60008181526018602090815260409182902082516101a08101845281546001600160a01b03908116825260018301548116938201939093526002820154909216928201929092526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460ff808216151560e0840152610100808304821615159084015262010000820481161515610120840152630100000090910416158015610140830152600883015461016083015260099092015461018082015291925061278f57336000908152601c602052604090205460ff1661278a5760405162461bcd60e51b81526004016110799061588e565b6127d1565b336001600160a01b03841614806127b55750336000908152601c602052604090205460ff165b6127d15760405162461bcd60e51b81526004016110799061588e565b6127dd828583336142ee565b50506115426001600755565b606060006127f7601961451e565b905060008167ffffffffffffffff8111156128145761281461595a565b6040519080825280602002602001820160405280156128ab57816020015b604080516101a08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082015282526000199092019101816128325790505b50905060005b828110156129bf57601860006128c8601984614528565b8152602080820192909252604090810160002081516101a08101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460ff808216151560e0850152610100808304821615159085015262010000820481161515610120850152630100000090910416151561014083015260088101546101608301526009015461018082015282518390839081106129a1576129a1615970565b602002602001018190525080806129b790615986565b9150506128b1565b5092915050565b6000546001600160a01b031633146129f05760405162461bcd60e51b8152600401611079906157d4565b601f91909155602055565b6000546001600160a01b03163314612a255760405162461bcd60e51b8152600401611079906157d4565b601e55565b3360009081526012602052604081205460ff16612a595760405162461bcd60e51b81526004016110799061588e565b601654600e54808210612a6e57509050611124565b80851115612a7a578094505b84821015612bd7576000600e8381548110612a9757612a97615970565b6000918252602090912001546040516327b42c0f60e01b8152600481018290526001600160a01b038716602482015290915030906327b42c0f906044016020604051808303816000875af1925050508015612b0f575060408051601f3d908101601f19168201909252612b0c91810190615834565b60015b612b985760405163225fc9fd60e01b8152600481018290526001600160a01b0386166024820152309063225fc9fd906044016020604051808303816000875af1925050508015612b7c575060408051601f3d908101601f19168201909252612b7991810190615834565b60015b612b865750612a7a565b80612b92575050612bd7565b50612ba6565b80612ba4575050612bd7565b505b600e8381548110612bb957612bb9615970565b600091825260208220015582612bce81615986565b93505050612a7a565b5060168190559392505050565b612bec61396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c639190615834565b15612c805760405162461bcd60e51b815260040161107990615851565b600154604051631e3451e360e01b81526001600160a01b038a8116600483015290911690631e3451e390602401602060405180830381865afa158015612cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cee9190615834565b612d235760405162461bcd60e51b815260206004820152600660248201526509e9a74d2c8f60d31b6044820152606401611079565b833414612d425760405162461bcd60e51b81526004016110799061586f565b81151580612d4f57508015155b15612d72578215612d725760405162461bcd60e51b8152600401611079906158ae565b8115801590612d8057508015155b15612db757600b54612d9390600261580d565b841015612db25760405162461bcd60e51b815260040161107990615737565b612e01565b8215612ddf57600a54841015612db25760405162461bcd60e51b815260040161107990615737565b600b54841015612e015760405162461bcd60e51b815260040161107990615737565b88888888888787878215612e6357612e246001600160a01b03861633308b614534565b602054881015612e465760405162461bcd60e51b81526004016110799061599f565b612e5e3389878a8a89898b15600a5460016000613e73565b612e9e565b8915612e8057612e80336000878a8a89888b600b54600080613e73565b8815612e9e57612e9e336000878a8a89878b15600b54600080613e73565b5050505050505050612eb06001600755565b505050505050505050565b6000612ec561396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3c9190615834565b15612f595760405162461bcd60e51b815260040161107990615851565b600154604051631e3451e360e01b81526001600160a01b038b8116600483015290911690631e3451e390602401602060405180830381865afa158015612fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc79190615834565b612ffc5760405162461bcd60e51b815260206004820152600660248201526509e9a74d2c8f60d31b6044820152606401611079565b34821461301b5760405162461bcd60e51b81526004016110799061586f565b83158015613027575082155b156130535760085482101561304e5760405162461bcd60e51b81526004016110799061586f565b6130da565b831580159061306157508215155b156130a057600b5461307490600261580d565b60085461308191906159bd565b82101561304e5760405162461bcd60e51b81526004016110799061586f565b600b546130ae90600161580d565b6008546130bb91906159bd565b8210156130da5760405162461bcd60e51b81526004016110799061586f565b601f548810156130fc5760405162461bcd60e51b81526004016110799061599f565b6131116001600160a01b038b1633308b614534565b6000613125338c8c8c8c8c8c60085461456c565b90508415613144576131443360008d8d8c8c8b8e600b54600080613e73565b8315613162576131623360008d8d8c8c8a8e15600b54600080613e73565b905061316e6001600755565b9998505050505050505050565b6131ee60405180610140016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081525090565b600e54821061320f5760405162461bcd60e51b8152600401611079906158ae565b6000801b600e838154811061322657613226615970565b90600052602060002001540361324e5760405162461bcd60e51b8152600401611079906158ae565b600d6000600e848154811061326557613265615970565b60009182526020808320909101548352828101939093526040918201902081516101408101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460ff16151560a0830152600681015460c0830152600781015460e083015260088101546101008301526009015461012082015292915050565b336000908152601c602052604090205460ff166133395760405162461bcd60e51b81526004016110799061588e565b8360005b818110156134015730636410659a88888481811061335d5761335d615970565b90506020020160208101906133729190615183565b87878581811061338457613384615970565b6040516001600160e01b031960e087901b1681526001600160a01b039485166004820152602090910292909201356024830152509086166044820152606401600060405180830381600087803b1580156133dd57600080fd5b505af19250505080156133ee575060015b50806133f981615986565b91505061333d565b50505050505050565b6040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b61345961396a565b600060186000613469338861340a565b8152602081019190915260400160002080549091506001600160a01b03166134a35760405162461bcd60e51b8152600401611079906158ae565b6003810154600782015462010000900460ff161561354f576020548410156134dd5760405162461bcd60e51b81526004016110799061599f565b8084116000816134f6576134f1868461576b565b613500565b613500838761576b565b90508115613527576001840154613522906001600160a01b0316333084614534565b613545565b83546001850154613545916001600160a01b03918216911683613ba3565b5050600382018490555b6005820183905560048201859055600782015460018301546002840154600385015460405160ff62010000860481161515953395600080516020615be4833981519152956135cb956001600160a01b039283169591909216938f938f928e92808316926101008104821692630100000090910490911690615909565b60405180910390a350506135df6001600755565b50505050565b6000546001600160a01b0316331461360f5760405162461bcd60e51b8152600401611079906157d4565b600891909155600955565b336000908152601d602052604090205460ff166136495760405162461bcd60e51b81526004016110799061588e565b8160005b818110156136ed576001546001600160a01b031663e75a4a2c86868481811061367857613678615970565b90506020020135856040518363ffffffff1660e01b81526004016136af9291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b1580156136c957600080fd5b505af19250505080156136da575060015b50806136e581615986565b91505061364d565b5050505050565b6000546001600160a01b0316331461371e5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000908152600560205260408120549081900361374457505050565b6001600160a01b038316600081815260056020526040812055613768908383613ba3565b604080516001600160a01b038086168252841660208201529081018290527f4f1b51dd7a2fcb861aa2670f668be66835c4ee12b4bbbf037e4d0018f39819e490606001611b21565b3360009081526012602052604081205460ff166137df5760405162461bcd60e51b81526004016110799061588e565b6017546011548082106137f457509050611124565b80851115613800578094505b8482101561395d5760006011838154811061381d5761381d615970565b600091825260209091200154604051630d4d003d60e01b8152600481018290526001600160a01b03871660248201529091503090630d4d003d906044016020604051808303816000875af1925050508015613895575060408051601f3d908101601f1916820190925261389291810190615834565b60015b61391e57604051633051b17160e11b8152600481018290526001600160a01b038616602482015230906360a362e2906044016020604051808303816000875af1925050508015613902575060408051601f3d908101601f191682019092526138ff91810190615834565b60015b61390c5750613800565b8061391857505061395d565b5061392c565b8061392a57505061395d565b505b6011838154811061393f5761393f615970565b60009182526020822001558261395481615986565b93505050613800565b5060178190559392505050565b60026007540361398d57604051633ee5aeb560e01b815260040160405180910390fd5b6002600755565b6000601554836139a491906159bd565b42106139db5760405162461bcd60e51b815260206004820152600660248201526504f4d3a6578760d41b6044820152606401611079565b6139e684848461468d565b90505b9392505050565b60008084613a6b5760035460405163286d59ad60e11b81526001600160a01b038981166004830152909116906350dab35a90602401602060405180830381865afa158015613a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a6691906157f4565b613ad9565b600354604051631b1c2b2360e11b81526001600160a01b03898116600483015290911690633638564690602401602060405180830381865afa158015613ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad991906157f4565b90508415613b065782811015613b015760405162461bcd60e51b8152600401611079906159d0565b613b26565b82811115613b265760405162461bcd60e51b8152600401611079906159d0565b600154604051633cae4d0160e11b81526001600160a01b039091169063795c9a0290613b60908c908c908c908c908c908c906004016158cf565b6020604051808303816000875af1158015613b7f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316e91906157f4565b6040516001600160a01b03831660248201526044810182905261254490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614741565b60006139e684848461468d565b6000613c26878787878787600454614813565b15613caa576000612710600654612710613c40919061576b565b613c4a908861580d565b613c5491906159ef565b90506000613c62828861576b565b6001600160a01b038916600090815260056020526040902054909150613c899082906159bd565b6001600160a01b038916600090815260056020526040902055509050613cad565b50835b9695505050505050565b600082613d3157600354604051631b1c2b2360e11b81526001600160a01b03878116600483015290911690633638564690602401602060405180830381865afa158015613d08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2c91906157f4565b613d9f565b60035460405163286d59ad60e11b81526001600160a01b038781166004830152909116906350dab35a90602401602060405180830381865afa158015613d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9f91906157f4565b90508215613dcc5781811115613dc75760405162461bcd60e51b8152600401611079906159d0565b613dec565b81811015613dec5760405162461bcd60e51b8152600401611079906159d0565b6001546040516348d91abf60e01b81526001600160a01b03898116600483015288811660248301528781166044830152606482018790528515156084830152909116906348d91abf9060a401600060405180830381600087803b158015613e5257600080fd5b505af1158015613e66573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038b166000908152601b60205260409020548b908b908b908b908b908b908b908b908b908b908b90613ead8160016159bd565b6001600160a01b038d166000908152601b6020526040812091909155613ed38d8361340a565b9050604051806101a001604052808e6001600160a01b031681526020018c6001600160a01b031681526020018b6001600160a01b031681526020018d81526020018a81526020018881526020018681526020018915158152602001871515815260200185151581526020018415158152602001838152602001428152506018600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548160ff0219169083151502179055506101008201518160070160016101000a81548160ff0219169083151502179055506101208201518160070160026101000a81548160ff0219169083151502179055506101408201518160070160036101000a81548160ff021916908315150217905550610160820151816008015561018082015181600901559050506140b9601982614a17565b506140c48d83614a23565b505050505050505050505050505050505050505050505050565b600154604051634a3f088d60e01b81526001600160a01b0387811660048301528681166024830152858116604483015284151560648301526000928392911690634a3f088d9060840161016060405180830381865afa158015614145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141699190615a54565b90508281608001511015614181576000915050614187565b60019150505b95945050505050565b6000806040518061014001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b031681526020018881526020018715158152602001866001600160a01b0316815260200185815260200184815260200143815260200142815250905060008061420d83614bbd565b9150915082600001516001600160a01b03167fa04ce72776d6eacadbfa98056fa95f0d1c17edf59cd5a86311242bf7e190272884602001518560400151866060015187608001518860a001518960c001518a60e001518a6001601180549050614276919061576b565b604080516001600160a01b039a8b168152988a1660208a0152880196909652931515606087015295909116608085015260a084015260c083019390935260e08201929092526101008101919091524361012082015242610140820152610160015b60405180910390a29b9a5050505050505050505050565b81516001600160a01b03166143155760405162461bcd60e51b8152600401611079906158ae565b600084815260186020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101829055600581018290556006810182905560078101805463ffffffff191690556008810182905560090155614389601985614512565b50816101200151156143b6578151606083015160208401516143b6926001600160a01b0390911691613ba3565b8161014001516144365760c08201516040516000916001600160a01b038416918381818185875af1925050503d806000811461440e576040519150601f19603f3d011682016040523d82523d6000602084013e614413565b606091505b50509050806144345760405162461bcd60e51b815260040161107990615737565b505b816101200151151582600001516001600160a01b03167f9baccefcc549a2604631907e5ed0fc1e156943afa56b8da2277721800b5fb0158460200151856040015187876060015188608001518960a001518a60c001518b60e001518c61010001518d61014001516040516144b39a99989796959493929190615b03565b60405180910390a38151602083015160408085015161014086015191516000946001600160a01b031693600080516020615be4833981519152936145049391928a9188918291829182918291615909565b60405180910390a350505050565b60006139e98383614d17565b6000611124825490565b60006139e98383614e0a565b6040516001600160a01b03808516602483015283166044820152606481018290526135df9085906323b872dd60e01b90608401613bcf565b6000806040518061014001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b0316815260200188815260200187815260200186151581526020018581526020018481526020014381526020014281525090506000806145e083614e34565b915091508b6001600160a01b03167f030190664051033b47fa29bb4639c1e5c2efac367a1071e4cbb970508870f4db8c8c8c8c8c8c8c8a6001600e80549050614629919061576b565b604080516001600160a01b039a8b1681529990981660208a0152968801959095526060870193909352901515608086015260a085015260c084015260e083015261010082015243610120820152426101408201523a610160820152610180016142d7565b6000333014806146ac57503360009081526012602052604090205460ff165b156146c95743601354856146c091906159bd565b111590506139e9565b336001600160a01b038316146146f15760405162461bcd60e51b81526004016110799061588e565b426014548461470091906159bd565b11156147375760405162461bcd60e51b81526004016110799060208082526004908201526313d34e9960e21b604082015260600190565b5060019392505050565b6000614796826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614f739092919063ffffffff16565b80519091501561254457808060200190518101906147b49190615834565b6125445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611079565b60008260000361482557506001611aa3565b600154604051634a3f088d60e01b81526001600160a01b038a811660048301528981166024830152878116604483015286151560648301526000921690634a3f088d9060840161016060405180830381865afa158015614889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ad9190615a54565b608081015160a08201519192509060008290036148d05760009350505050611aa3565b60006148dc87846159bd565b600254604051630a48d5a960e01b81526001600160a01b038e81166004830152602482018e905292935060009290911690630a48d5a990604401602060405180830381865afa158015614933573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061495791906157f4565b9050600061496582856159bd565b90506000846149766127108861580d565b61498091906159ef565b90506000826149918b6127106159bd565b61499b908761580d565b6149a591906159ef565b905081811015614a015760408051858152602081018490529081018290527f3f6e9241514ae172d9872f51274a73fd6b370b2f8fa612669bb17d933078860c9060600160405180910390a1600198505050505050505050611aa3565b5060009f9e505050505050505050505050505050565b60006139e98383614f82565b600060186000614a33858561340a565b8152602080820192909252604090810160002081516101a08101835281546001600160a01b0390811682526001830154811694820185905260028301548116828501819052600384015460608401819052600485015460808501819052600586015460a08601819052600687015460c08701819052600788015460ff808216151560e08a0181905261010080840483161515908b01819052620100008404831615156101208c01819052630100000090940490921615156101408b0181905260088c01546101608c01526009909b01546101808b01529a51989c50909a968e16997fc9a016c895f4c3fd94ea06c606c2bad25bbfded616bd87d92bbe8845e342d8dd99614b47998f97969594939190615b03565b60405180910390a38061012001511515836001600160a01b0316600080516020615be48339815191528360200151846040015186866060015187608001518860a001518960e001518a61010001518b6101400151604051614bb099989796959493929190615909565b60405180910390a3505050565b80516001600160a01b0381166000908152600f6020526040812054909182918290614be99060016159bd565b6001600160a01b0383166000908152600f60205260408120829055909150614c11838361340a565b60008181526010602090815260408083208a5181546001600160a01b03199081166001600160a01b03928316178355938c015160018084018054871692841692909217909155928c01516002830180549095169082161790935560608b0151600382015560808b015160048201805460a08e01516001600160a81b0319909116921515610100600160a81b031916929092176101009290951682029490941790935560c08b0151600582015560e08b01516006820155918a015160078301556101209099015160089091015560118054988901815590527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68909601869055509492505050565b60008181526001830160205260408120548015614e00576000614d3b60018361576b565b8554909150600090614d4f9060019061576b565b9050818114614db4576000866000018281548110614d6f57614d6f615970565b9060005260206000200154905080876000018481548110614d9257614d92615970565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614dc557614dc5615b5a565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611124565b6000915050611124565b6000826000018281548110614e2157614e21615970565b9060005260206000200154905092915050565b80516001600160a01b0381166000908152600c6020526040812054909182918290614e609060016159bd565b6001600160a01b0383166000908152600c60205260408120829055909150614e88838361340a565b6000818152600d602090815260408083208a5181546001600160a01b03199081166001600160a01b03928316178355938c015160018084018054871692841692909217909155928c015160028301805490951691161790925560608a0151600383015560808a0151600483015560a08a015160058301805460ff191691151591909117905560c08a0151600683015560e08a015160078301556101008a0151600883015561012090990151600990910155600e8054988901815590527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909601869055509492505050565b60606139e68484600085614fd1565b6000818152600183016020526040812054614fc957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611124565b506000611124565b6060824710156150325760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611079565b843b6150805760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611079565b600080866001600160a01b0316858760405161509c9190615b94565b60006040518083038185875af1925050503d80600081146150d9576040519150601f19603f3d011682016040523d82523d6000602084013e6150de565b606091505b5091509150611aa3828286606083156150f85750816139e9565b8251156151085782518084602001fd5b8160405162461bcd60e51b81526004016110799190615bb0565b60006020828403121561513457600080fd5b5035919050565b6001600160a01b038116811461515057600080fd5b50565b6000806040838503121561516657600080fd5b8235915060208301356151788161513b565b809150509250929050565b60006020828403121561519557600080fd5b81356139e98161513b565b801515811461515057600080fd5b600080604083850312156151c157600080fd5b82356151cc8161513b565b91506020830135615178816151a0565b600080604083850312156151ef57600080fd5b82356151fa8161513b565b946020939093013593505050565b600080600080600080600060e0888a03121561522357600080fd5b873561522e8161513b565b9650602088013561523e8161513b565b9550604088013594506060880135615255816151a0565b935060808801356152658161513b565b9699959850939692959460a0840135945060c09093013592915050565b60008060006060848603121561529757600080fd5b505081359360208301359350604090920135919050565b600080604083850312156152c157600080fd5b50508035926020909101359150565b600080600080608085870312156152e657600080fd5b84356152f1816151a0565b93506020850135925060408501356153088161513b565b91506060850135615318816151a0565b939692955090935050565b60008060006060848603121561533857600080fd5b83356153438161513b565b925060208401359150604084013561535a8161513b565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b8281101561543257815180516001600160a01b03908116865287820151811688870152868201511686860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e080820151151590860152610100808201511515908601526101208082015115159086015261014080820151151590860152610160808201519086015261018090810151908501526101a09093019290850190600101615382565b5091979650505050505050565b60008060008060008060008060006101208a8c03121561545e57600080fd5b8935985060208a01356154708161513b565b975060408a0135965060608a01356154878161513b565b955060808a0135615497816151a0565b989b979a50959894979660a0860135965060c08601359560e0810135955061010001359350915050565b60008060008060008060008060006101208a8c0312156154e057600080fd5b89356154eb8161513b565b985060208a01356154fb8161513b565b975060408a0135965060608a0135955060808a0135615497816151a0565b81516001600160a01b031681526101408101602083015161554560208401826001600160a01b03169052565b50604083015161556060408401826001600160a01b03169052565b50606083015160608301526080830151608083015260a083015161558860a084018215159052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60008083601f8401126155cd57600080fd5b50813567ffffffffffffffff8111156155e557600080fd5b6020830191508360208260051b850101111561560057600080fd5b9250929050565b60008060008060006060868803121561561f57600080fd5b853567ffffffffffffffff8082111561563757600080fd5b61564389838a016155bb565b9097509550602088013591508082111561565c57600080fd5b50615669888289016155bb565b909450925050604086013561567d8161513b565b809150509295509295909350565b600080600080608085870312156156a157600080fd5b5050823594602084013594506040840135936060013592509050565b6000806000604084860312156156d257600080fd5b833567ffffffffffffffff8111156156e957600080fd5b6156f5868287016155bb565b909450925050602084013561535a8161513b565b6000806040838503121561571c57600080fd5b82356157278161513b565b915060208301356151788161513b565b60208082526004908201526327a69d3360e11b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8181038181111561112457611124615755565b6001600160a01b03998a16815297891660208901526040880196909652931515606087015291909516608085015260a084019490945260c083019390935260e08201929092526101008101919091526101200190565b602080825260069082015265424d3a34303360d01b604082015260600190565b60006020828403121561580657600080fd5b5051919050565b808202811582820484141761112457611124615755565b805161582f816151a0565b919050565b60006020828403121561584657600080fd5b81516139e9816151a0565b60208082526004908201526304f4d3a360e41b604082015260600190565b60208082526005908201526427a69d32b360d91b604082015260600190565b6020808252600690820152654f4d3a34303360d01b604082015260600190565b60208082526007908201526613d34e99985a5b60ca1b604082015260600190565b6001600160a01b0396871681529486166020860152928516604085015260608401919091521515608083015290911660a082015260c00190565b6001600160a01b03998a16815297909816602088015260408701959095526060860193909352608085019190915260a0840152151560c0830152151560e08201529015156101008201526101200190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161599857615998615755565b5060010190565b6020808252600490820152634f4d3a6360e01b604082015260600190565b8082018082111561112457611124615755565b6020808252600590820152640424d3a6d760dc1b604082015260600190565b600082615a0c57634e487b7160e01b600052601260045260246000fd5b500490565b604051610160810167ffffffffffffffff81118282101715615a4357634e487b7160e01b600052604160045260246000fd5b60405290565b805161582f8161513b565b60006101608284031215615a6757600080fd5b615a6f615a11565b615a7883615a49565b8152615a8660208401615a49565b6020820152615a9760408401615a49565b6040820152615aa860608401615824565b60608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152508091505092915050565b6001600160a01b039a8b16815298909916602089015260408801969096526060870194909452608086019290925260a085015260c0840152151560e083015215156101008201529015156101208201526101400190565b634e487b7160e01b600052603160045260246000fd5b60005b83811015615b8b578181015183820152602001615b73565b50506000910152565b60008251615ba6818460208701615b70565b9190910192915050565b6020815260008251806020840152615bcf816040850160208701615b70565b601f01601f1916919091016040019291505056fed21a7b68c66e053c73bd8bed4d752fc154d5a35d095063cd99a7b35b3787df27a26469706673582212206b312c268f47a78023de687dabeb35c58a337e9ba1c6a34c01e38fd7d4ad3f6164736f6c63430008130033000000000000000000000000082321f9939373b02ad54ea214bf6e822531e679000000000000000000000000ed2f56432a9af01328ca53b4dc1c8ec822869f9a00000000000000000000000011905d2def1071c84e6f835d16e220066d092df900000000000000000000000000000000000000000000000000016bcc41e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000090f560000000000000000000000000000000000000000000000000000000000090f560

Deployed ByteCode

0x6080604052600436106103ce5760003560e01c80636410659a116101fd578063a5a89c0911610118578063ddef7e85116100ab578063f3883d8b1161007a578063f3883d8b14610cef578063f851a44014610d0f578063fa44457714610d2f578063faf990f314610d5c578063fbfa77cf14610e3757600080fd5b8063ddef7e8514610c7a578063e4d8f76814610c9a578063eea3f2f614610cba578063f255527814610ccf57600080fd5b8063c66a29f0116100e7578063c66a29f014610c0e578063cb0269c914610c2e578063cefdb8b614610c44578063dd53831614610c6457600080fd5b8063a5a89c0914610b9b578063a915e53b14610bae578063ad988fea14610bc1578063ae5efa2b14610bee57600080fd5b80638d60b392116101905780639a2081001161015f5780639a20810014610a395780639b57862014610a595780639c3e86ca14610a6f5780639c3f1e9014610a8457600080fd5b80638d60b392146109cd57806394ac7ec0146109ed57806398d1e03a14610a03578063990269e514610a1957600080fd5b8063704b6c02116101cc578063704b6c021461094b578063724e78da1461096b5780637323a7d31461098b5780637bea0d1c146109ab57600080fd5b80636410659a146108d557806367a52793146108f55780636817031b1461090b578063699535011461092b57600080fd5b80633833f5f5116102ed578063529a356f116102805780635b4c58df1161024f5780635b4c58df146108265780635b8d97751461085b57806360a362e214610888578063633451de146108a857600080fd5b8063529a356f146107885780635841fcaa146107b8578063590f2113146107ce5780635a29638d1461080657600080fd5b806343a28ba9116102bc57806343a28ba9146107125780634440423e146107285780634453a37414610748578063490ae2101461076857600080fd5b80633833f5f5146106965780633a2a80c7146106c65780633b0befca146106dc5780634067b132146106f257600080fd5b8063225fc9fd116103655780633422ead1116103345780633422ead11461061d578063347c91aa1461063d57806335d4a1031461065057806336eba48a1461066657600080fd5b8063225fc9fd146105a75780632327361d146105c757806327b42c0f146105e75780632953cb7a1461060757600080fd5b80631bca8cf0116103a15780631bca8cf0146104625780631ce9cb8f146104785780631e261538146104a55780631f285106146104c757600080fd5b806304225954146103d35780630c40f430146104065780630d4d003d1461041c578063126082cf1461044c575b600080fd5b3480156103df57600080fd5b506103f36103ee366004615122565b610e57565b6040519081526020015b60405180910390f35b34801561041257600080fd5b506103f360085481565b34801561042857600080fd5b5061043c610437366004615153565b610e78565b60405190151581526020016103fd565b34801561045857600080fd5b506103f361271081565b34801561046e57600080fd5b506103f360175481565b34801561048457600080fd5b506103f3610493366004615183565b60056020526000908152604090205481565b3480156104b157600080fd5b506104c56104c03660046151ae565b61112a565b005b3480156104d357600080fd5b506105426104e2366004615122565b6010602052600090815260409020805460018201546002830154600384015460048501546005860154600687015460078801546008909801546001600160a01b03978816989688169795861696949560ff8516956101009095041693908a565b604080516001600160a01b039b8c168152998b1660208b0152978a169789019790975260608801959095529215156080870152951660a085015260c084019490945260e0830193909352610100820192909252610120810191909152610140016103fd565b3480156105b357600080fd5b5061043c6105c2366004615153565b6111b4565b3480156105d357600080fd5b506104c56105e23660046151dc565b61145b565b3480156105f357600080fd5b5061043c610602366004615153565b611546565b34801561061357600080fd5b506103f360095481565b34801561062957600080fd5b506104c56106383660046151ae565b6118e3565b6103f361064b366004615208565b611965565b34801561065c57600080fd5b506103f360205481565b34801561067257600080fd5b5061043c610681366004615183565b60126020526000908152604090205460ff1681565b3480156106a257600080fd5b5061043c6106b1366004615183565b601c6020526000908152604090205460ff1681565b3480156106d257600080fd5b506103f360145481565b3480156106e857600080fd5b506103f3601e5481565b3480156106fe57600080fd5b506104c561070d366004615282565b611aae565b34801561071e57600080fd5b506103f3601f5481565b34801561073457600080fd5b506104c56107433660046152ae565b611b2e565b34801561075457600080fd5b506104c56107633660046151ae565b611b63565b34801561077457600080fd5b506104c5610783366004615122565b611be5565b34801561079457600080fd5b5061043c6107a3366004615183565b601d6020526000908152604090205460ff1681565b3480156107c457600080fd5b506103f360135481565b3480156107da57600080fd5b506003546107ee906001600160a01b031681565b6040516001600160a01b0390911681526020016103fd565b34801561081257600080fd5b506002546107ee906001600160a01b031681565b34801561083257600080fd5b506108466108413660046152d0565b611c14565b604080519283529015156020830152016103fd565b34801561086757600080fd5b506103f3610876366004615183565b601b6020526000908152604090205481565b34801561089457600080fd5b5061043c6108a3366004615153565b611ce2565b3480156108b457600080fd5b506103f36108c3366004615183565b600c6020526000908152604090205481565b3480156108e157600080fd5b506104c56108f0366004615323565b611f1c565b34801561090157600080fd5b506103f360065481565b34801561091757600080fd5b506104c5610926366004615183565b612549565b34801561093757600080fd5b506104c5610946366004615183565b612595565b34801561095757600080fd5b506104c5610966366004615183565b6125e1565b34801561097757600080fd5b506104c5610986366004615183565b61262d565b34801561099757600080fd5b506104c56109a6366004615153565b612679565b3480156109b757600080fd5b506109c06127e9565b6040516103fd9190615365565b3480156109d957600080fd5b506104c56109e83660046152ae565b6129c6565b3480156109f957600080fd5b506103f3600b5481565b348015610a0f57600080fd5b506103f360045481565b348015610a2557600080fd5b506104c5610a34366004615122565b6129fb565b348015610a4557600080fd5b506103f3610a54366004615153565b612a2a565b348015610a6557600080fd5b506103f360165481565b348015610a7b57600080fd5b50600e546103f3565b348015610a9057600080fd5b50610b20610a9f366004615122565b60186020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b03988916999789169890961696949593949293919260ff808316936101008404821693620100008104831693630100000090910490921691908d565b604080516001600160a01b039e8f1681529c8e1660208e01529a909c16998b019990995260608a0197909752608089019590955260a088019390935260c0870191909152151560e08601521515610100850152151561012084015215156101408301526101608201526101808101919091526101a0016103fd565b6104c5610ba936600461543f565b612be4565b6103f3610bbc3660046154c1565b612ebb565b348015610bcd57600080fd5b50610be1610bdc366004615122565b61317b565b6040516103fd9190615519565b348015610bfa57600080fd5b506104c5610c09366004615607565b61330a565b348015610c1a57600080fd5b506103f3610c293660046151dc565b61340a565b348015610c3a57600080fd5b506103f360155481565b348015610c5057600080fd5b506104c5610c5f36600461568b565b613451565b348015610c7057600080fd5b506103f3600a5481565b348015610c8657600080fd5b506104c5610c953660046152ae565b6135e5565b348015610ca657600080fd5b506104c5610cb53660046156bd565b61361a565b348015610cc657600080fd5b506011546103f3565b348015610cdb57600080fd5b506104c5610cea366004615709565b6136f4565b348015610cfb57600080fd5b506103f3610d0a366004615153565b6137b0565b348015610d1b57600080fd5b506000546107ee906001600160a01b031681565b348015610d3b57600080fd5b506103f3610d4a366004615183565b600f6020526000908152604090205481565b348015610d6857600080fd5b50610dda610d77366004615122565b600d6020526000908152604090208054600182015460028301546003840154600485015460058601546006870154600788015460088901546009909901546001600160a01b039889169997891698909616969495939460ff90931693919290918a565b604080516001600160a01b039b8c168152998b1660208b0152979099169688019690965260608701949094526080860192909252151560a085015260c084015260e0830152610100820152610120810191909152610140016103fd565b348015610e4357600080fd5b506001546107ee906001600160a01b031681565b600e8181548110610e6757600080fd5b600091825260209091200154905081565b6000610e8261396a565b60008381526010602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015481169482019490945260038201546060820152600482015460ff8116151560808301526101009081900490941660a0820152600582015460c0820152600682015460e082015260078201549381019390935260080154610120830152610f2a57600191505061111a565b610f438161010001518261012001518360000151613994565b610f5157600091505061111a565b600084815260106020908152604080832080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018490556004810180546001600160a81b0319169055600581018490556006810184905560078101849055600801839055835191840151908401516060850151608086015160c0870151610fe495949392919030906139f0565b60a08301516020840151919250611005916001600160a01b03169083613ba3565b60e08201516040516000916001600160a01b038716918381818185875af1925050503d8060008114611053576040519150601f19603f3d011682016040523d82523d6000602084013e611058565b606091505b50509050806110825760405162461bcd60e51b815260040161107990615737565b60405180910390fd5b82600001516001600160a01b03167fbece414bdfb172bf1b798de2a8ecc3c86ec25ad7011ee97f4e3549715137b5ef84602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151436110e5919061576b565b6101208d01516110f5904261576b565b60405161110a9998979695949392919061577e565b60405180910390a2600193505050505b6111246001600755565b92915050565b6000546001600160a01b031633146111545760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000818152601c6020908152604091829020805460ff191685151590811790915591519182527f1d5bc0255b943d6a5b5279e8a55d74d620baccbceecb25e87a3558f14c4c118e91015b60405180910390a25050565b60006111be61396a565b6000838152600d602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460ff16151560a0840152600681015460c0840152600781015460e084015260088101546101008401526009015461012083015261125e57600191505061111a565b6112778161010001518261012001518360000151613c06565b61128557600091505061111a565b6000848152600d60209081526040822080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018390556004810183905560058101805460ff19169055600681018390556007810183905560088101839055600901919091558151606083015191830151611311926001600160a01b039091169190613ba3565b60e08101516040516000916001600160a01b038616918381818185875af1925050503d806000811461135f576040519150601f19603f3d011682016040523d82523d6000602084013e611364565b606091505b50509050806113855760405162461bcd60e51b815260040161107990615737565b81600001516001600160a01b03167fb46dc78d7a64b7dd9e215a1a5955b8e522c417f8260520d97a2ce9a73c72bd1283602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151436113e8919061576b565b6101208c01516113f8904261576b565b604080516001600160a01b039a8b1681529990981660208a0152968801959095526060870193909352901515608086015260a085015260c084015260e0830152610100820152610120015b60405180910390a26001925050506111246001600755565b6000546001600160a01b031633146114855760405162461bcd60e51b8152600401611079906157d4565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156114c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ed91906157f4565b8111156115285760405162461bcd60e51b815260206004820152600960248201526813d34e985b5bdd5b9d60ba1b6044820152606401611079565b600054611542906001600160a01b03848116911683613ba3565b5050565b600061155061396a565b6000838152600d602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460ff16151560a0840152600681015460c0840152600781015460e08401526008810154610100840152600901546101208301526115f057600191505061111a565b6116098161010001518261012001518360000151613994565b61161757600091505061111a565b6000848152600d6020908152604080832080546001600160a01b031990811682556001808301805483169055600283018054909216909155600382018590556004820185905560058201805460ff19169055600682018590556007820185905560088201859055600990910193909355915483519184015160608501519385015160a086015160808701516116d7966001600160a01b03909516956116c29590949390929091613c13565b60208401516001600160a01b03169190613ba3565b6116fd81600001518260200151836040015184608001518560a001518660c00151613cb7565b60e08101516040516000916001600160a01b038616918381818185875af1925050503d806000811461174b576040519150601f19603f3d011682016040523d82523d6000602084013e611750565b606091505b50509050806117715760405162461bcd60e51b815260040161107990615737565b608082015115611880576000600260009054906101000a90046001600160a01b03166001600160a01b0316635dc271d684608001518560a001518660c00151601e5488606001516117c2919061580d565b60208901516040516001600160e01b031960e088901b16815260048101959095529215156024850152604484019190915260648301526001600160a01b0316608482015260a4016020604051808303816000875af1158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c91906157f4565b905061187e836000015160008560200151866040015187608001518860a00151878a60a00151600b5460006001613e73565b505b81600001516001600160a01b03167f02ca30b520a08cead06dc4eb7847b9df09adf21e5e07dd7d2d8c32381fecb75283602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151436113e8919061576b565b6000546001600160a01b0316331461190d5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b038216600081815260126020908152604091829020805460ff191685151590811790915591519182527ffbabc02389290a451c6e600d05bf9887b99bfad39d8e1237e4e3df042e4941fe91016111a8565b600061196f61396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e69190615834565b15611a035760405162461bcd60e51b815260040161107990615851565b600954821015611a255760405162461bcd60e51b815260040161107990615737565b348214611a445760405162461bcd60e51b81526004016110799061586f565b611a51338989888a6140de565b611a875760405162461bcd60e51b81526020600482015260076024820152664f4d3a73697a6560c81b6044820152606401611079565b611a973389898989898989614190565b9050611aa36001600755565b979650505050505050565b6000546001600160a01b03163314611ad85760405162461bcd60e51b8152600401611079906157d4565b60138390556014829055601581905560408051848152602081018490529081018290527fb98e759701eaca2e60c25e91109003c1c7442ef731b5d569037063005da8254d906060015b60405180910390a1505050565b6000546001600160a01b03163314611b585760405162461bcd60e51b8152600401611079906157d4565b600a91909155600b55565b6000546001600160a01b03163314611b8d5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000818152601d6020908152604091829020805460ff191685151590811790915591519182527f8c0d56805c3b43d441481229dc64bee168253ffe4305f37ab7cfe63b1c4268c691016111a8565b6000546001600160a01b03163314611c0f5760405162461bcd60e51b8152600401611079906157d4565b600655565b6003546040516311b5088f60e31b81526001600160a01b0384811660048301526000928392839290911690638da8447890602401602060405180830381865afa158015611c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8991906157f4565b9050600087611c9a57868210611c9e565b8682115b905080611cd55760405162461bcd60e51b815260206004820152600560248201526427a69d383960d91b6044820152606401611079565b9097909650945050505050565b6000611cec61396a565b60008381526010602090815260409182902082516101408101845281546001600160a01b039081168083526001840154821694830194909452600283015481169482019490945260038201546060820152600482015460ff8116151560808301526101009081900490941660a0820152600582015460c0820152600682015460e082015260078201549381019390935260080154610120830152611d9457600191505061111a565b611dad8161010001518261012001518360000151613c06565b611dbb57600091505061111a565b60008481526010602052604080822080546001600160a01b03199081168255600182018054821690556002820180549091169055600381018390556004810180546001600160a81b031916905560058101839055600681018390556007810183905560080182905560e083015190516001600160a01b03861691908381818185875af1925050503d8060008114611e6e576040519150601f19603f3d011682016040523d82523d6000602084013e611e73565b606091505b5050905080611e945760405162461bcd60e51b815260040161107990615737565b81600001516001600160a01b03167fd2c665be6c7dd696827595026252b33f769220c8a4d2813d855c5d393afc158c83602001518460400151856060015186608001518760a001518860c001518960e001518a610100015143611ef7919061576b565b6101208c0151611f07904261576b565b6040516114439998979695949392919061577e565b611f2461396a565b336000908152601c602052604090205460ff16611f535760405162461bcd60e51b81526004016110799061588e565b6000611f5f848461340a565b60008181526018602090815260409182902082516101a08101845281546001600160a01b039081168083526001840154821694830194909452600283015416938101939093526003810154606084015260048101546080840152600581015460a0840152600681015460c0840152600781015460ff808216151560e08601526101008083048216151590860152620100008204811615156101208601526301000000909104161515610140840152600881015461016084015260090154610180830152919250906120425760405162461bcd60e51b8152600401611079906158ae565b60006120618261010001518360a0015184604001518560e00151611c14565b509050816101200151156122385760015460608301516020840151612094926001600160a01b0391821692911690613ba3565b60015482516020840151604080860151608087015160e088015192516348d91abf60e01b81526001600160a01b039586166004820152938516602485015290841660448401526064830152151560848201529116906348d91abf9060a401600060405180830381600087803b15801561210c57600080fd5b505af1158015612120573d6000803e3d6000fd5b50505050608082015115612233576000600260009054906101000a90046001600160a01b03166001600160a01b0316635dc271d684608001518560e001518660a00151601e548860600151612175919061580d565b60208901516040516001600160e01b031960e088901b16815260048101959095529215156024850152604484019190915260648301526001600160a01b0316608482015260a4016020604051808303816000875af11580156121db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ff91906157f4565b9050612231836000015160008560200151866040015187608001518860e00151878a60e00151600b5460006001613e73565b505b61232b565b600061225b8360000151846020015185604001518660e0015187608001516140de565b9050806122775761226e848785886142ee565b5050505061253a565b60015483516020850151604080870151608088015160e08901519251633cae4d0160e11b81526000966001600160a01b03169563795c9a02956122c79591949093909290919030906004016158cf565b6020604051808303816000875af11580156122e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230a91906157f4565b84516020860151919250612328916001600160a01b03169083613ba3565b50505b600083815260186020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101829055600581018290556006810182905560078101805463ffffffff19169055600881018290556009015561239f601984614512565b5060c08201516040516000916001600160a01b038716918381818185875af1925050503d80600081146123ee576040519150601f19603f3d011682016040523d82523d6000602084013e6123f3565b606091505b50509050806124145760405162461bcd60e51b815260040161107990615737565b826101200151151583600001516001600160a01b03167ff24fdd74c4b1144dd9f57bc5cc659cf1cfc0a71cff35b366ff486c212510d9bb856020015186604001518a886060015189608001518a60a001518b60c001518b8d60e001518e61010001516040516124dc9a999897969594939291906001600160a01b039a8b16815298909916602089015260408801969096526060870194909452608086019290925260a085015260c084015260e083015215156101008201529015156101208201526101400190565b60405180910390a38251602084015160408086015161014087015191516000946001600160a01b031693600080516020615be48339815191529361252d9391928d9188918291829182918291615909565b60405180910390a3505050505b6125446001600755565b505050565b6000546001600160a01b031633146125735760405162461bcd60e51b8152600401611079906157d4565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146125bf5760405162461bcd60e51b8152600401611079906157d4565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461260b5760405162461bcd60e51b8152600401611079906157d4565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146126575760405162461bcd60e51b8152600401611079906157d4565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b61268161396a565b600061268d828461340a565b60008181526018602090815260409182902082516101a08101845281546001600160a01b03908116825260018301548116938201939093526002820154909216928201929092526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460ff808216151560e0840152610100808304821615159084015262010000820481161515610120840152630100000090910416158015610140830152600883015461016083015260099092015461018082015291925061278f57336000908152601c602052604090205460ff1661278a5760405162461bcd60e51b81526004016110799061588e565b6127d1565b336001600160a01b03841614806127b55750336000908152601c602052604090205460ff165b6127d15760405162461bcd60e51b81526004016110799061588e565b6127dd828583336142ee565b50506115426001600755565b606060006127f7601961451e565b905060008167ffffffffffffffff8111156128145761281461595a565b6040519080825280602002602001820160405280156128ab57816020015b604080516101a08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082015282526000199092019101816128325790505b50905060005b828110156129bf57601860006128c8601984614528565b8152602080820192909252604090810160002081516101a08101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460ff808216151560e0850152610100808304821615159085015262010000820481161515610120850152630100000090910416151561014083015260088101546101608301526009015461018082015282518390839081106129a1576129a1615970565b602002602001018190525080806129b790615986565b9150506128b1565b5092915050565b6000546001600160a01b031633146129f05760405162461bcd60e51b8152600401611079906157d4565b601f91909155602055565b6000546001600160a01b03163314612a255760405162461bcd60e51b8152600401611079906157d4565b601e55565b3360009081526012602052604081205460ff16612a595760405162461bcd60e51b81526004016110799061588e565b601654600e54808210612a6e57509050611124565b80851115612a7a578094505b84821015612bd7576000600e8381548110612a9757612a97615970565b6000918252602090912001546040516327b42c0f60e01b8152600481018290526001600160a01b038716602482015290915030906327b42c0f906044016020604051808303816000875af1925050508015612b0f575060408051601f3d908101601f19168201909252612b0c91810190615834565b60015b612b985760405163225fc9fd60e01b8152600481018290526001600160a01b0386166024820152309063225fc9fd906044016020604051808303816000875af1925050508015612b7c575060408051601f3d908101601f19168201909252612b7991810190615834565b60015b612b865750612a7a565b80612b92575050612bd7565b50612ba6565b80612ba4575050612bd7565b505b600e8381548110612bb957612bb9615970565b600091825260208220015582612bce81615986565b93505050612a7a565b5060168190559392505050565b612bec61396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c639190615834565b15612c805760405162461bcd60e51b815260040161107990615851565b600154604051631e3451e360e01b81526001600160a01b038a8116600483015290911690631e3451e390602401602060405180830381865afa158015612cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cee9190615834565b612d235760405162461bcd60e51b815260206004820152600660248201526509e9a74d2c8f60d31b6044820152606401611079565b833414612d425760405162461bcd60e51b81526004016110799061586f565b81151580612d4f57508015155b15612d72578215612d725760405162461bcd60e51b8152600401611079906158ae565b8115801590612d8057508015155b15612db757600b54612d9390600261580d565b841015612db25760405162461bcd60e51b815260040161107990615737565b612e01565b8215612ddf57600a54841015612db25760405162461bcd60e51b815260040161107990615737565b600b54841015612e015760405162461bcd60e51b815260040161107990615737565b88888888888787878215612e6357612e246001600160a01b03861633308b614534565b602054881015612e465760405162461bcd60e51b81526004016110799061599f565b612e5e3389878a8a89898b15600a5460016000613e73565b612e9e565b8915612e8057612e80336000878a8a89888b600b54600080613e73565b8815612e9e57612e9e336000878a8a89878b15600b54600080613e73565b5050505050505050612eb06001600755565b505050505050505050565b6000612ec561396a565b600160009054906101000a90046001600160a01b03166001600160a01b031663ef9465c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f3c9190615834565b15612f595760405162461bcd60e51b815260040161107990615851565b600154604051631e3451e360e01b81526001600160a01b038b8116600483015290911690631e3451e390602401602060405180830381865afa158015612fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc79190615834565b612ffc5760405162461bcd60e51b815260206004820152600660248201526509e9a74d2c8f60d31b6044820152606401611079565b34821461301b5760405162461bcd60e51b81526004016110799061586f565b83158015613027575082155b156130535760085482101561304e5760405162461bcd60e51b81526004016110799061586f565b6130da565b831580159061306157508215155b156130a057600b5461307490600261580d565b60085461308191906159bd565b82101561304e5760405162461bcd60e51b81526004016110799061586f565b600b546130ae90600161580d565b6008546130bb91906159bd565b8210156130da5760405162461bcd60e51b81526004016110799061586f565b601f548810156130fc5760405162461bcd60e51b81526004016110799061599f565b6131116001600160a01b038b1633308b614534565b6000613125338c8c8c8c8c8c60085461456c565b90508415613144576131443360008d8d8c8c8b8e600b54600080613e73565b8315613162576131623360008d8d8c8c8a8e15600b54600080613e73565b905061316e6001600755565b9998505050505050505050565b6131ee60405180610140016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081525090565b600e54821061320f5760405162461bcd60e51b8152600401611079906158ae565b6000801b600e838154811061322657613226615970565b90600052602060002001540361324e5760405162461bcd60e51b8152600401611079906158ae565b600d6000600e848154811061326557613265615970565b60009182526020808320909101548352828101939093526040918201902081516101408101835281546001600160a01b03908116825260018301548116948201949094526002820154909316918301919091526003810154606083015260048101546080830152600581015460ff16151560a0830152600681015460c0830152600781015460e083015260088101546101008301526009015461012082015292915050565b336000908152601c602052604090205460ff166133395760405162461bcd60e51b81526004016110799061588e565b8360005b818110156134015730636410659a88888481811061335d5761335d615970565b90506020020160208101906133729190615183565b87878581811061338457613384615970565b6040516001600160e01b031960e087901b1681526001600160a01b039485166004820152602090910292909201356024830152509086166044820152606401600060405180830381600087803b1580156133dd57600080fd5b505af19250505080156133ee575060015b50806133f981615986565b91505061333d565b50505050505050565b6040516bffffffffffffffffffffffff19606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b61345961396a565b600060186000613469338861340a565b8152602081019190915260400160002080549091506001600160a01b03166134a35760405162461bcd60e51b8152600401611079906158ae565b6003810154600782015462010000900460ff161561354f576020548410156134dd5760405162461bcd60e51b81526004016110799061599f565b8084116000816134f6576134f1868461576b565b613500565b613500838761576b565b90508115613527576001840154613522906001600160a01b0316333084614534565b613545565b83546001850154613545916001600160a01b03918216911683613ba3565b5050600382018490555b6005820183905560048201859055600782015460018301546002840154600385015460405160ff62010000860481161515953395600080516020615be4833981519152956135cb956001600160a01b039283169591909216938f938f928e92808316926101008104821692630100000090910490911690615909565b60405180910390a350506135df6001600755565b50505050565b6000546001600160a01b0316331461360f5760405162461bcd60e51b8152600401611079906157d4565b600891909155600955565b336000908152601d602052604090205460ff166136495760405162461bcd60e51b81526004016110799061588e565b8160005b818110156136ed576001546001600160a01b031663e75a4a2c86868481811061367857613678615970565b90506020020135856040518363ffffffff1660e01b81526004016136af9291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b1580156136c957600080fd5b505af19250505080156136da575060015b50806136e581615986565b91505061364d565b5050505050565b6000546001600160a01b0316331461371e5760405162461bcd60e51b8152600401611079906157d4565b6001600160a01b0382166000908152600560205260408120549081900361374457505050565b6001600160a01b038316600081815260056020526040812055613768908383613ba3565b604080516001600160a01b038086168252841660208201529081018290527f4f1b51dd7a2fcb861aa2670f668be66835c4ee12b4bbbf037e4d0018f39819e490606001611b21565b3360009081526012602052604081205460ff166137df5760405162461bcd60e51b81526004016110799061588e565b6017546011548082106137f457509050611124565b80851115613800578094505b8482101561395d5760006011838154811061381d5761381d615970565b600091825260209091200154604051630d4d003d60e01b8152600481018290526001600160a01b03871660248201529091503090630d4d003d906044016020604051808303816000875af1925050508015613895575060408051601f3d908101601f1916820190925261389291810190615834565b60015b61391e57604051633051b17160e11b8152600481018290526001600160a01b038616602482015230906360a362e2906044016020604051808303816000875af1925050508015613902575060408051601f3d908101601f191682019092526138ff91810190615834565b60015b61390c5750613800565b8061391857505061395d565b5061392c565b8061392a57505061395d565b505b6011838154811061393f5761393f615970565b60009182526020822001558261395481615986565b93505050613800565b5060178190559392505050565b60026007540361398d57604051633ee5aeb560e01b815260040160405180910390fd5b6002600755565b6000601554836139a491906159bd565b42106139db5760405162461bcd60e51b815260206004820152600660248201526504f4d3a6578760d41b6044820152606401611079565b6139e684848461468d565b90505b9392505050565b60008084613a6b5760035460405163286d59ad60e11b81526001600160a01b038981166004830152909116906350dab35a90602401602060405180830381865afa158015613a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a6691906157f4565b613ad9565b600354604051631b1c2b2360e11b81526001600160a01b03898116600483015290911690633638564690602401602060405180830381865afa158015613ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ad991906157f4565b90508415613b065782811015613b015760405162461bcd60e51b8152600401611079906159d0565b613b26565b82811115613b265760405162461bcd60e51b8152600401611079906159d0565b600154604051633cae4d0160e11b81526001600160a01b039091169063795c9a0290613b60908c908c908c908c908c908c906004016158cf565b6020604051808303816000875af1158015613b7f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316e91906157f4565b6040516001600160a01b03831660248201526044810182905261254490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614741565b60006139e684848461468d565b6000613c26878787878787600454614813565b15613caa576000612710600654612710613c40919061576b565b613c4a908861580d565b613c5491906159ef565b90506000613c62828861576b565b6001600160a01b038916600090815260056020526040902054909150613c899082906159bd565b6001600160a01b038916600090815260056020526040902055509050613cad565b50835b9695505050505050565b600082613d3157600354604051631b1c2b2360e11b81526001600160a01b03878116600483015290911690633638564690602401602060405180830381865afa158015613d08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d2c91906157f4565b613d9f565b60035460405163286d59ad60e11b81526001600160a01b038781166004830152909116906350dab35a90602401602060405180830381865afa158015613d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9f91906157f4565b90508215613dcc5781811115613dc75760405162461bcd60e51b8152600401611079906159d0565b613dec565b81811015613dec5760405162461bcd60e51b8152600401611079906159d0565b6001546040516348d91abf60e01b81526001600160a01b03898116600483015288811660248301528781166044830152606482018790528515156084830152909116906348d91abf9060a401600060405180830381600087803b158015613e5257600080fd5b505af1158015613e66573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038b166000908152601b60205260409020548b908b908b908b908b908b908b908b908b908b908b90613ead8160016159bd565b6001600160a01b038d166000908152601b6020526040812091909155613ed38d8361340a565b9050604051806101a001604052808e6001600160a01b031681526020018c6001600160a01b031681526020018b6001600160a01b031681526020018d81526020018a81526020018881526020018681526020018915158152602001871515815260200185151581526020018415158152602001838152602001428152506018600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e08201518160070160006101000a81548160ff0219169083151502179055506101008201518160070160016101000a81548160ff0219169083151502179055506101208201518160070160026101000a81548160ff0219169083151502179055506101408201518160070160036101000a81548160ff021916908315150217905550610160820151816008015561018082015181600901559050506140b9601982614a17565b506140c48d83614a23565b505050505050505050505050505050505050505050505050565b600154604051634a3f088d60e01b81526001600160a01b0387811660048301528681166024830152858116604483015284151560648301526000928392911690634a3f088d9060840161016060405180830381865afa158015614145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141699190615a54565b90508281608001511015614181576000915050614187565b60019150505b95945050505050565b6000806040518061014001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b031681526020018881526020018715158152602001866001600160a01b0316815260200185815260200184815260200143815260200142815250905060008061420d83614bbd565b9150915082600001516001600160a01b03167fa04ce72776d6eacadbfa98056fa95f0d1c17edf59cd5a86311242bf7e190272884602001518560400151866060015187608001518860a001518960c001518a60e001518a6001601180549050614276919061576b565b604080516001600160a01b039a8b168152988a1660208a0152880196909652931515606087015295909116608085015260a084015260c083019390935260e08201929092526101008101919091524361012082015242610140820152610160015b60405180910390a29b9a5050505050505050505050565b81516001600160a01b03166143155760405162461bcd60e51b8152600401611079906158ae565b600084815260186020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101829055600581018290556006810182905560078101805463ffffffff191690556008810182905560090155614389601985614512565b50816101200151156143b6578151606083015160208401516143b6926001600160a01b0390911691613ba3565b8161014001516144365760c08201516040516000916001600160a01b038416918381818185875af1925050503d806000811461440e576040519150601f19603f3d011682016040523d82523d6000602084013e614413565b606091505b50509050806144345760405162461bcd60e51b815260040161107990615737565b505b816101200151151582600001516001600160a01b03167f9baccefcc549a2604631907e5ed0fc1e156943afa56b8da2277721800b5fb0158460200151856040015187876060015188608001518960a001518a60c001518b60e001518c61010001518d61014001516040516144b39a99989796959493929190615b03565b60405180910390a38151602083015160408085015161014086015191516000946001600160a01b031693600080516020615be4833981519152936145049391928a9188918291829182918291615909565b60405180910390a350505050565b60006139e98383614d17565b6000611124825490565b60006139e98383614e0a565b6040516001600160a01b03808516602483015283166044820152606481018290526135df9085906323b872dd60e01b90608401613bcf565b6000806040518061014001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001896001600160a01b0316815260200188815260200187815260200186151581526020018581526020018481526020014381526020014281525090506000806145e083614e34565b915091508b6001600160a01b03167f030190664051033b47fa29bb4639c1e5c2efac367a1071e4cbb970508870f4db8c8c8c8c8c8c8c8a6001600e80549050614629919061576b565b604080516001600160a01b039a8b1681529990981660208a0152968801959095526060870193909352901515608086015260a085015260c084015260e083015261010082015243610120820152426101408201523a610160820152610180016142d7565b6000333014806146ac57503360009081526012602052604090205460ff165b156146c95743601354856146c091906159bd565b111590506139e9565b336001600160a01b038316146146f15760405162461bcd60e51b81526004016110799061588e565b426014548461470091906159bd565b11156147375760405162461bcd60e51b81526004016110799060208082526004908201526313d34e9960e21b604082015260600190565b5060019392505050565b6000614796826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614f739092919063ffffffff16565b80519091501561254457808060200190518101906147b49190615834565b6125445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611079565b60008260000361482557506001611aa3565b600154604051634a3f088d60e01b81526001600160a01b038a811660048301528981166024830152878116604483015286151560648301526000921690634a3f088d9060840161016060405180830381865afa158015614889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ad9190615a54565b608081015160a08201519192509060008290036148d05760009350505050611aa3565b60006148dc87846159bd565b600254604051630a48d5a960e01b81526001600160a01b038e81166004830152602482018e905292935060009290911690630a48d5a990604401602060405180830381865afa158015614933573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061495791906157f4565b9050600061496582856159bd565b90506000846149766127108861580d565b61498091906159ef565b90506000826149918b6127106159bd565b61499b908761580d565b6149a591906159ef565b905081811015614a015760408051858152602081018490529081018290527f3f6e9241514ae172d9872f51274a73fd6b370b2f8fa612669bb17d933078860c9060600160405180910390a1600198505050505050505050611aa3565b5060009f9e505050505050505050505050505050565b60006139e98383614f82565b600060186000614a33858561340a565b8152602080820192909252604090810160002081516101a08101835281546001600160a01b0390811682526001830154811694820185905260028301548116828501819052600384015460608401819052600485015460808501819052600586015460a08601819052600687015460c08701819052600788015460ff808216151560e08a0181905261010080840483161515908b01819052620100008404831615156101208c01819052630100000090940490921615156101408b0181905260088c01546101608c01526009909b01546101808b01529a51989c50909a968e16997fc9a016c895f4c3fd94ea06c606c2bad25bbfded616bd87d92bbe8845e342d8dd99614b47998f97969594939190615b03565b60405180910390a38061012001511515836001600160a01b0316600080516020615be48339815191528360200151846040015186866060015187608001518860a001518960e001518a61010001518b6101400151604051614bb099989796959493929190615909565b60405180910390a3505050565b80516001600160a01b0381166000908152600f6020526040812054909182918290614be99060016159bd565b6001600160a01b0383166000908152600f60205260408120829055909150614c11838361340a565b60008181526010602090815260408083208a5181546001600160a01b03199081166001600160a01b03928316178355938c015160018084018054871692841692909217909155928c01516002830180549095169082161790935560608b0151600382015560808b015160048201805460a08e01516001600160a81b0319909116921515610100600160a81b031916929092176101009290951682029490941790935560c08b0151600582015560e08b01516006820155918a015160078301556101209099015160089091015560118054988901815590527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68909601869055509492505050565b60008181526001830160205260408120548015614e00576000614d3b60018361576b565b8554909150600090614d4f9060019061576b565b9050818114614db4576000866000018281548110614d6f57614d6f615970565b9060005260206000200154905080876000018481548110614d9257614d92615970565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614dc557614dc5615b5a565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611124565b6000915050611124565b6000826000018281548110614e2157614e21615970565b9060005260206000200154905092915050565b80516001600160a01b0381166000908152600c6020526040812054909182918290614e609060016159bd565b6001600160a01b0383166000908152600c60205260408120829055909150614e88838361340a565b6000818152600d602090815260408083208a5181546001600160a01b03199081166001600160a01b03928316178355938c015160018084018054871692841692909217909155928c015160028301805490951691161790925560608a0151600383015560808a0151600483015560a08a015160058301805460ff191691151591909117905560c08a0151600683015560e08a015160078301556101008a0151600883015561012090990151600990910155600e8054988901815590527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909601869055509492505050565b60606139e68484600085614fd1565b6000818152600183016020526040812054614fc957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611124565b506000611124565b6060824710156150325760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611079565b843b6150805760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611079565b600080866001600160a01b0316858760405161509c9190615b94565b60006040518083038185875af1925050503d80600081146150d9576040519150601f19603f3d011682016040523d82523d6000602084013e6150de565b606091505b5091509150611aa3828286606083156150f85750816139e9565b8251156151085782518084602001fd5b8160405162461bcd60e51b81526004016110799190615bb0565b60006020828403121561513457600080fd5b5035919050565b6001600160a01b038116811461515057600080fd5b50565b6000806040838503121561516657600080fd5b8235915060208301356151788161513b565b809150509250929050565b60006020828403121561519557600080fd5b81356139e98161513b565b801515811461515057600080fd5b600080604083850312156151c157600080fd5b82356151cc8161513b565b91506020830135615178816151a0565b600080604083850312156151ef57600080fd5b82356151fa8161513b565b946020939093013593505050565b600080600080600080600060e0888a03121561522357600080fd5b873561522e8161513b565b9650602088013561523e8161513b565b9550604088013594506060880135615255816151a0565b935060808801356152658161513b565b9699959850939692959460a0840135945060c09093013592915050565b60008060006060848603121561529757600080fd5b505081359360208301359350604090920135919050565b600080604083850312156152c157600080fd5b50508035926020909101359150565b600080600080608085870312156152e657600080fd5b84356152f1816151a0565b93506020850135925060408501356153088161513b565b91506060850135615318816151a0565b939692955090935050565b60008060006060848603121561533857600080fd5b83356153438161513b565b925060208401359150604084013561535a8161513b565b809150509250925092565b602080825282518282018190526000919060409081850190868401855b8281101561543257815180516001600160a01b03908116865287820151811688870152868201511686860152606080820151908601526080808201519086015260a0808201519086015260c0808201519086015260e080820151151590860152610100808201511515908601526101208082015115159086015261014080820151151590860152610160808201519086015261018090810151908501526101a09093019290850190600101615382565b5091979650505050505050565b60008060008060008060008060006101208a8c03121561545e57600080fd5b8935985060208a01356154708161513b565b975060408a0135965060608a01356154878161513b565b955060808a0135615497816151a0565b989b979a50959894979660a0860135965060c08601359560e0810135955061010001359350915050565b60008060008060008060008060006101208a8c0312156154e057600080fd5b89356154eb8161513b565b985060208a01356154fb8161513b565b975060408a0135965060608a0135955060808a0135615497816151a0565b81516001600160a01b031681526101408101602083015161554560208401826001600160a01b03169052565b50604083015161556060408401826001600160a01b03169052565b50606083015160608301526080830151608083015260a083015161558860a084018215159052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b60008083601f8401126155cd57600080fd5b50813567ffffffffffffffff8111156155e557600080fd5b6020830191508360208260051b850101111561560057600080fd5b9250929050565b60008060008060006060868803121561561f57600080fd5b853567ffffffffffffffff8082111561563757600080fd5b61564389838a016155bb565b9097509550602088013591508082111561565c57600080fd5b50615669888289016155bb565b909450925050604086013561567d8161513b565b809150509295509295909350565b600080600080608085870312156156a157600080fd5b5050823594602084013594506040840135936060013592509050565b6000806000604084860312156156d257600080fd5b833567ffffffffffffffff8111156156e957600080fd5b6156f5868287016155bb565b909450925050602084013561535a8161513b565b6000806040838503121561571c57600080fd5b82356157278161513b565b915060208301356151788161513b565b60208082526004908201526327a69d3360e11b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8181038181111561112457611124615755565b6001600160a01b03998a16815297891660208901526040880196909652931515606087015291909516608085015260a084019490945260c083019390935260e08201929092526101008101919091526101200190565b602080825260069082015265424d3a34303360d01b604082015260600190565b60006020828403121561580657600080fd5b5051919050565b808202811582820484141761112457611124615755565b805161582f816151a0565b919050565b60006020828403121561584657600080fd5b81516139e9816151a0565b60208082526004908201526304f4d3a360e41b604082015260600190565b60208082526005908201526427a69d32b360d91b604082015260600190565b6020808252600690820152654f4d3a34303360d01b604082015260600190565b60208082526007908201526613d34e99985a5b60ca1b604082015260600190565b6001600160a01b0396871681529486166020860152928516604085015260608401919091521515608083015290911660a082015260c00190565b6001600160a01b03998a16815297909816602088015260408701959095526060860193909352608085019190915260a0840152151560c0830152151560e08201529015156101008201526101200190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006001820161599857615998615755565b5060010190565b6020808252600490820152634f4d3a6360e01b604082015260600190565b8082018082111561112457611124615755565b6020808252600590820152640424d3a6d760dc1b604082015260600190565b600082615a0c57634e487b7160e01b600052601260045260246000fd5b500490565b604051610160810167ffffffffffffffff81118282101715615a4357634e487b7160e01b600052604160045260246000fd5b60405290565b805161582f8161513b565b60006101608284031215615a6757600080fd5b615a6f615a11565b615a7883615a49565b8152615a8660208401615a49565b6020820152615a9760408401615a49565b6040820152615aa860608401615824565b60608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101208084015181830152506101408084015181830152508091505092915050565b6001600160a01b039a8b16815298909916602089015260408801969096526060870194909452608086019290925260a085015260c0840152151560e083015215156101008201529015156101208201526101400190565b634e487b7160e01b600052603160045260246000fd5b60005b83811015615b8b578181015183820152602001615b73565b50506000910152565b60008251615ba6818460208701615b70565b9190910192915050565b6020815260008251806020840152615bcf816040850160208701615b70565b601f01601f1916919091016040019291505056fed21a7b68c66e053c73bd8bed4d752fc154d5a35d095063cd99a7b35b3787df27a26469706673582212206b312c268f47a78023de687dabeb35c58a337e9ba1c6a34c01e38fd7d4ad3f6164736f6c63430008130033