ETH Price: $2,213.70 (-6.02%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Trading

Compiler Version
v0.7.3+commit.9bfce1f6

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
pragma solidity ^0.7.3;
pragma experimental ABIEncoderV2;

import '@openzeppelin/contracts/math/SafeMath.sol';

import './interfaces/IProducts.sol';
import './interfaces/IQueue.sol';
import './interfaces/IToken.sol';
import './interfaces/ITreasury.sol';

import './libraries/Permit.sol';
import './libraries/SafeMathExt.sol';
import './libraries/UintSet.sol';

contract Trading {

    /* Libraries */

    using SafeMath for uint256;
    using SafeMathExt for uint256;
    using UintSet for UintSet.Set;

    /* Structs */

    struct Position {
        address sender; // 20 bytes
        bytes12 symbol; // 12 bytes
        uint64 margin; // 8 bytes
        uint64 leverage; // 8 bytes
        uint64 price; // 8 bytes
        uint48 block; // 7 bytes
        bool isBuy; // 1 byte
        uint256 id; // not stored
    }

    /* Variables */

    address private products;
    address private queue;
    address private treasury;

    // DAI
    address public currency;

    // minimum margin to open a position
    uint256 public minimumMargin;

    // 10^18 for DAI
    uint256 public currencyUnit;

    // user => balance
    mapping(address => uint256) public freeMargins;

    // id => Position
    mapping(uint256 => Position) public positions;

    // user => position ids
    mapping(address => UintSet.Set) private userPositionIds;

    // positions being liquidated
    mapping(uint256 => bool) public liquidatingIds;

    // user => bool
    mapping(address => uint256) public pausedUsers;

    // liquidator reward %
    uint256 public liquidatorReward;

    address public owner;
    bool private initialized;
    bool public paused;

    /* Events */
    event NewContracts(address products, address queue, address treasury);
    event NewMinimum(uint256 amount);
    event NewLiquidatorReward(uint256 amount);
    event Deposited(uint256 amount);
    event Withdrew(uint256 amount);

    event OrderSubmitted(
        uint256 id,
        address indexed sender,
        bool isBuy,
        bytes32 symbol,
        uint256 margin,
        uint256 leverage,
        uint256 positionId
    );

    event OrderCancelled(
        uint256 id,
        uint256 positionId,
        address indexed sender,
        string reason
    );

    event PositionOpened(
        uint256 positionId,
        address indexed sender,
        bool isBuy,
        bytes32 symbol,
        uint256 margin,
        uint256 leverage,
        uint256 price
    );

    event PositionLiquidated(
        uint256 positionId,
        address indexed sender,
        address indexed liquidator,
        uint256 marginLiquidated
    );

    event PositionClosed(
        uint256 positionId,
        address indexed sender,
        uint256 marginClosed,
        uint256 amountToReturn,
        uint256 entryPrice,
        uint256 price,
        uint256 leverage
    );

    event LiquidationSubmitted(
        uint256 id,
        uint256 positionId,
        address indexed sender
    );

    /* Initializer (called only once) */

    function initialize(address _currency) public {
        require(!initialized, '!initialized');
        initialized = true;
        owner = msg.sender;
        liquidatorReward = 10;
        currency = _currency;
        currencyUnit = SafeMathExt.base10pow(IToken(_currency).decimals());
    }

    /* Methods called by governance */

    function registerContracts(
        address _products,
        address _queue,
        address _treasury
    ) external onlyOwner {
        products = _products;
        queue = _queue;
        treasury = _treasury;
        emit NewContracts(_products, _queue, _treasury);
    }

    function setCurrencyMin(uint256 _amount) external onlyOwner {
        minimumMargin = _amount;
        emit NewMinimum(_amount);
    }

    function setLiquidatorReward(uint256 _amount) external onlyOwner {
        require(_amount <= 100, '!percent');
        liquidatorReward = _amount;
        emit NewLiquidatorReward(_amount);
    }

    function pauseUsers(address[] calldata users) external onlyOwner {
        for (uint256 i = 0; i < users.length; i++) {
            pausedUsers[users[i]] = block.number;
        }
    }

    function unpauseUsers(address[] calldata users) external onlyOwner {
        for (uint256 i = 0; i < users.length; i++) {
            pausedUsers[users[i]] = 0;
        }
    }

    // TODO review
    function capUserBalance(
        address user,
        uint256 newBalanceCap
    ) external onlyOwner {
        // user must be blocked in a previous transaction before we can cap the balance
        uint256 pauseBlockNumber = pausedUsers[user];
        require(pauseBlockNumber > 0 && pauseBlockNumber < block.number, '!user_not_paused');
        uint256 treasuryBalance = ITreasury(treasury).getUserBalance(user);
        // trading balance and newBalance are 8 decimals, treasuryBalance 18 decimals (in most cases)
        require(newBalanceCap.mulDecimal8(currencyUnit) >= treasuryBalance, '!too_low');
        if (freeMargins[user] > newBalanceCap) {
            freeMargins[user] = newBalanceCap;
        }
    }

    function pause() external onlyOwner {
        paused = true;
    }

    function unpause() external onlyOwner {
        paused = false;
    }

    /* Methods called by the client */

    function deposit(
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external whenNotPaused {
        uint256 amt = amount.mulDecimal8(currencyUnit);
        Permit.permit(currency, amt, msg.sender, treasury, deadline, v, r, s);
        ITreasury(treasury).userDeposit(msg.sender, amt);
        freeMargins[msg.sender] = freeMargins[msg.sender].add(amount);
        emit Deposited(amount);
    }

    function withdraw(
        uint256 amount
    ) external whenNotPaused whenNotUserPaused(msg.sender) {
        freeMargins[msg.sender] = freeMargins[msg.sender].sub(amount, '!balance');
        ITreasury(treasury).userWithdraw(msg.sender, amount.mulDecimal8(currencyUnit));
        emit Withdrew(amount);
    }

    function submitOrder(
        bool isBuy,
        bytes32 symbol,
        uint256 margin,
        uint256 leverage
    ) external whenNotPaused whenNotUserPaused(msg.sender) {
        require(margin >= minimumMargin, '!margin');
        require(leverage >= SafeMathExt.UNIT8, '!leverage');
        uint256 maxLeverage = IProducts(products).getMaxLeverage(symbol, true);
        require(maxLeverage > 0, '!symbol');
        require(leverage <= maxLeverage, '!max_leverage');
        freeMargins[msg.sender] = freeMargins[msg.sender].sub(margin, '!balance');
        uint256 id = _queueOrder(isBuy, symbol, margin, leverage, 0, address(0));
        positions[id] = Position({isBuy: isBuy, margin: SafeMathExt.safeUint64(margin), leverage: SafeMathExt.safeUint64(leverage), sender: msg.sender, symbol: bytes12(''), price: 0, block: 0, id: 0});
    }

    function submitOrderUpdate(
        uint256 positionId,
        uint256 margin
    ) external whenNotPaused {
        Position storage position = positions[positionId];
        require(position.price > 0, '!found');
        require(position.sender == msg.sender, '!authorized');
        // partial or full close
        require(margin <= uint256(position.margin), '!margin');
        _queueOrder(!position.isBuy, bytes32(position.symbol), margin, uint256(position.leverage), positionId, address(0));
    }

    function liquidatePositions(uint256[] calldata positionIds) external {
        uint256 length = positionIds.length;
        require(length < 6, '!too_many');
        for (uint256 i = 0; i < length; i++) {
            uint256 positionId = positionIds[i];
            Position storage position = positions[positionId];
            if (position.price > 0 && !liquidatingIds[positionId]) {
                liquidatingIds[positionId] = true;
                _queueOrder(!position.isBuy, bytes32(position.symbol), 0, 0, positionId, msg.sender);
            }
        }
    }

    function getUserPositions(address user) external view returns(Position[] memory _positions) {
        uint256 length = userPositionIds[user].length();
        _positions = new Position[](length);
        for (uint256 i=0; i < length; i++) {
            uint256 id = userPositionIds[user].at(i);
            Position memory positionWithId = positions[id];
            positionWithId.id = id;
            _positions[i] = positionWithId;
        }
        return _positions;
    }

    function getUserFreeMargin(address user) external view returns(uint256) {
        return freeMargins[user];
    }

    /* Queue methods */

    function processOrder(
        uint256 id,
        bytes32 symbol,
        uint256 price,
        uint256 margin,
        uint256 positionId,
        address liquidator
    ) external whenNotPaused onlyQueue {
        if (positionId > 0) {
            if (liquidator != address(0)) {
                delete liquidatingIds[positionId];
                Position memory position = positions[positionId];
                require(position.price > 0, '!found');
                uint256 positionMargin = uint256(position.margin);
                (uint256 pnl, bool isPnlNegative) = _calculatePnl(position, positionMargin, price);
                if (isPnlNegative && pnl >= positionMargin) {
                    _processLiquidation(liquidator, positionId, positionMargin, position.sender);
                }
            } else {
                _processClose(margin, price, positionId);
            }
        } else {
            _processOpen(id, symbol, price);
        }
    }

    function cancelOrder(
        uint256 id,
        uint256 positionId,
        address liquidator,
        string calldata reason
    ) external onlyQueue {
        if (positionId == 0) {
            // cancelling a new order
            Position storage position = positions[id];
            address sender = position.sender;
            uint256 margin = uint256(position.margin);
            delete positions[id];
            // release margin back to user
            freeMargins[sender] = freeMargins[sender].add(margin);
            emit OrderCancelled(id, id, sender, reason);
        } else if (liquidator != address(0)) {
            // cancelling a liquidation request
            delete liquidatingIds[id];
            emit OrderCancelled(id, positionId, liquidator, reason);
        } else {
            // cancelling a full or partial close order (sender could be address zero)
            emit OrderCancelled(id, positionId, positions[positionId].sender, reason);
        }
    }

    /* Internal methods */

    function _queueOrder(
        bool isBuy,
        bytes32 symbol,
        uint256 margin,
        uint256 leverage,
        uint256 positionId,
        address liquidator
    ) internal returns (uint256 id) {
        id = IQueue(queue).queueOrder(symbol, margin, positionId, liquidator);

        if (liquidator != address(0)) {
            emit LiquidationSubmitted(id, positionId, msg.sender);
        } else {
            emit OrderSubmitted(id, msg.sender, isBuy, symbol, margin, leverage, positionId);
        }
        return id;
    }

    function _processOpen(
        uint256 id,
        bytes32 symbol,
        uint256 price
    ) internal {
        Position storage position = positions[id];
        bool isBuy = position.isBuy;
        uint256 margin = uint256(position.margin);
        uint256 leverage = uint256(position.leverage);
        address sender = position.sender;
        // calculate execution price
        uint256 spread = IProducts(products).getSpread(symbol);
        if (isBuy) {
            price = price.mulDecimal8(SafeMathExt.UNIT8.add(spread));
        } else {
            price = price.mulDecimal8(SafeMathExt.UNIT8.sub(spread));
        }
        // complete the Position struct started in submitOrder
        position.symbol = bytes12(symbol);
        position.price = SafeMathExt.safeUint64(price);
        position.block = uint48(block.number);
        // user to position ID
        userPositionIds[sender].add(id);
        // event
        emit PositionOpened(id, sender, isBuy, symbol, margin, leverage, price);
    }

    function _processClose(
        uint256 margin,
        uint256 price,
        uint256 positionId
    ) internal {
        Position memory mPosition = positions[positionId];
        uint256 positionMargin = uint256(mPosition.margin);
        require(margin <= positionMargin, '!margin');
        uint256 spread = IProducts(products).getSpread(bytes32(mPosition.symbol));
        // execution price
        if (mPosition.isBuy) {
            price = price.mulDecimal8(SafeMathExt.UNIT8.sub(spread));
        } else {
            price = price.mulDecimal8(SafeMathExt.UNIT8.add(spread));
        }
        // pnl
        (uint256 pnl, bool isPnlNegative) = _calculatePnl(mPosition, margin, price);
        uint256 amountToReturn;
        if (isPnlNegative && pnl >= margin) {
            // position is liquidated
            delete positions[positionId];
            userPositionIds[mPosition.sender].remove(positionId);
            // transfer user margin to surplus
            ITreasury(treasury).collectFromUser(mPosition.sender, positionMargin.mulDecimal8(currencyUnit));
        } else {
            if (margin < positionMargin) {
                // partial close, update position margin
                Position storage position = positions[positionId];
                position.margin = SafeMathExt.safeUint64(positionMargin.sub(margin));
            } else {
                // full close, remove from mappings
                delete positions[positionId];
                userPositionIds[mPosition.sender].remove(positionId);
            }
            if (isPnlNegative) {
                amountToReturn = margin.sub(pnl);
                // return amountToReturn to free margin
                freeMargins[mPosition.sender] = freeMargins[mPosition.sender].add(amountToReturn);
                // collect pnl
                ITreasury(treasury).collectFromUser(mPosition.sender, pnl.mulDecimal8(currencyUnit));
            } else {
                amountToReturn = margin.add(pnl);
                freeMargins[mPosition.sender] = freeMargins[mPosition.sender].add(amountToReturn);
            }
        }
        emit PositionClosed(positionId, mPosition.sender, margin, amountToReturn, mPosition.price, price, mPosition.leverage);
    }

    function _processLiquidation(
        address liquidator,
        uint256 positionId,
        uint256 positionMargin,
        address positionSender
    ) internal {
        delete positions[positionId];
        userPositionIds[positionSender].remove(positionId);
        // collect margin from user
        ITreasury(treasury).collectFromUser(positionSender, positionMargin.mulDecimal8(currencyUnit));
        // pay liquidatorReward % of margin to liquidator
        uint256 liquidatorMargin = positionMargin.mul(liquidatorReward).div(100);
        freeMargins[liquidator] = freeMargins[liquidator].add(liquidatorMargin);
        emit PositionLiquidated(positionId, positionSender, liquidator, positionMargin);
    }

    /* Helpers */

    function _calculatePnl(
        Position memory position,
        uint256 margin,
        uint256 price
    ) internal view returns (uint256 pnl, bool isPnlNegative) {
        uint256 positionLeverage = uint256(position.leverage);
        uint256 positionPrice = uint256(position.price);
        if (position.isBuy) {
            if (price >= position.price) {
                pnl = margin.mul(positionLeverage).mul(price.sub(positionPrice)).div(positionPrice).div(SafeMathExt.UNIT8);
            } else {
                pnl = margin.mul(positionLeverage).mul(positionPrice.sub(price)).div(positionPrice).div(SafeMathExt.UNIT8);
                isPnlNegative = true;
            }
        } else {
            if (price > position.price) {
                pnl = margin.mul(positionLeverage).mul(price.sub(positionPrice)).div(positionPrice).div(SafeMathExt.UNIT8);
                isPnlNegative = true;
            } else {
                pnl = margin.mul(positionLeverage).mul(positionPrice.sub(price)).div(positionPrice).div(SafeMathExt.UNIT8);
            }
        }
        // Calculate funding to apply on this position
        uint256 fundingToApply = margin.mul(positionLeverage).mul(block.number.sub(uint256(position.block))).mul(IProducts(products).getFundingRate(bytes32(position.symbol))).div(1e16);
        // Subtract funding from pnl
        if (isPnlNegative) {
            pnl = pnl.add(fundingToApply);
        } else if (fundingToApply > pnl) {
            isPnlNegative = true;
            pnl = fundingToApply.sub(pnl);
        } else {
            pnl = pnl.sub(fundingToApply);
        }
        return (pnl, isPnlNegative);
    }

    /* Modifiers */

    modifier onlyOwner() {
        require(msg.sender == owner, '!authorized');
        _;
    }

    modifier onlyQueue() {
        require(msg.sender == queue, '!authorized');
        _;
    }

    modifier whenNotUserPaused(address user) {
        require(pausedUsers[user] == 0, '!pausedUser');
        _;
    }

    modifier whenNotPaused() {
        require(!paused, '!paused');
        _;
    }

}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

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

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

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

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

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

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

pragma solidity ^0.7.3;

interface IProducts {

	function getMaxLeverage(bytes32 symbol, bool checkDisabled) external view returns (uint256);
	function getFundingRate(bytes32 symbol) external view returns (uint256);
	function getSpread(bytes32 symbol) external view returns (uint256);

}

pragma solidity ^0.7.3;

interface IQueue {

    function firstOrderId() external view returns (uint256);
    function nextOrderId() external view returns (uint256);
    function processedOrdersCount() external view returns (uint256);

    function queueOrder(bytes32 symbol, uint256 margin, uint256 positionId, address liquidator) external returns (uint256);

}

pragma solidity ^0.7.3;

import './IEIP712.sol';

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IToken is IERC20, IEIP712 {

    /* ========== OPTIONAL VIEWS ========== */

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /* ========== VIEWS ========== */

    function paused() external view returns (bool);

    /* ========== MUTATIVE FUNCTIONS ========== */

    function initialize(address synthTrading, string memory _name, string memory _symbol) external;

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    function mint(address to, uint256 amount) external;
    function burn(uint256 amount) external;
    function burnFrom(address account, uint256 amount) external;

    function pause() external;
    function unpause() external;

}

pragma solidity ^0.7.3;

interface ITreasury {

    function userDeposit(address user, uint256 amount) external;
    function userWithdraw(address user, uint256 amount) external;
    function collectFromUser(address user, uint256 amount) external;
    function payToUser(address user, uint256 amount) external;
    
    function getUserBalance(address user) external view returns (uint256);

}

File 7 of 12 : Permit.sol
pragma solidity ^0.7.3;

import '../interfaces/IToken.sol';
import '../interfaces/IEIP712_DAI.sol';

library Permit {

	function permit(
		address currency,
		uint256 amount,
		address sender,
		address spender,
		uint256 deadline,
		uint8 v,
		bytes32 r,
		bytes32 s
	) internal {
		if (IToken(currency).allowance(sender, spender) < amount) {
		    if (keccak256(bytes(IToken(currency).symbol())) == 0xa5e92f3efb6826155f1f728e162af9d7cda33a574a1153b58f03ea01cc37e568) {
		        // DAI has a custom permit method
		        uint256 nonce = IToken(currency).nonces(sender);
		        IEIP712_DAI(currency).permit(sender, spender, nonce, deadline, true, v, r, s);
		    }/* else {
		        IToken(currency).permit(sender, spender, uint256(-1), deadline, v, r, s);
		    }*/
		}
	}

}

pragma solidity ^0.7.3;

import '@openzeppelin/contracts/math/SafeMath.sol';

library SafeMathExt {

    using SafeMath for uint256;

    uint256 public constant UNIT8 = 1e8;
    uint256 public constant UNIT18 = 1e18;

    function base10pow(uint8 exponent) internal pure returns (uint256) {
        // very common
        if (exponent == 18) return 1e18;
        if (exponent == 6) return 1e6;

        uint256 result = 1;

        while (exponent >= 10) {
            result = result.mul(uint256(1e10));
            exponent -= 10;
        }

        while (exponent > 0) {
            result = result.mul(uint256(10));
            exponent--;
        }

        return result;
    }

    function mulDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.mul(y) / UNIT18;
    }

    function divDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.mul(UNIT18).div(y);
    }

    function mulDecimal8(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.mul(y) / UNIT8;
    }

    function divDecimal8(uint256 x, uint256 y) internal pure returns (uint256) {
        return x.mul(UNIT8).div(y);
    }

    function safeUint64(uint256 x) internal pure returns (uint64) {
        require(x <= uint64(-1), 'SafeMath: cast overflow');
        return uint64(x);
    }

}

pragma solidity ^0.7.3;

library UintSet {

    struct Set {
        uint256[] _values;

        // Position of the value in the `values` array, plus 1 because index 0 means a value is not in the set
        mapping (uint256 => uint256) _indexes;
    }

    function add(Set storage set, uint256 value) internal 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;
        }
    }

    function remove(Set storage set, uint256 value) internal 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;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            uint256 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] = toDeleteIndex + 1; // All indexes are 1-based

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

    function contains(Set storage set, uint256 value) internal view returns (bool) {
        return set._indexes[value] != 0;
    }

    function length(Set storage set) internal view returns (uint256) {
        return set._values.length;
    }

    function at(Set storage set, uint256 index) internal view returns (uint256) {
        require(set._values.length > index, 'UintEnumerableSet: OUT_OF_BOUNDS');
        return set._values[index];
    }

}

pragma solidity ^0.7.3;

interface IEIP712 {

    /* ========== OPTIONAL VIEWS ========== */

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external view returns (bytes32);
    function nonces(address wallet) external view returns (uint256);

    /* ========== MUTATIVE FUNCTIONS ========== */

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;

}

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

pragma solidity ^0.7.3;

interface IEIP712_DAI {

    function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external;

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"LiquidationSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"products","type":"address"},{"indexed":false,"internalType":"address","name":"queue","type":"address"},{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"NewContracts","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NewLiquidatorReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NewMinimum","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"symbol","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"OrderSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginClosed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToReturn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entryPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"}],"name":"PositionClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginLiquidated","type":"uint256"}],"name":"PositionLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"symbol","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrew","type":"event"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"string","name":"reason","type":"string"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"newBalanceCap","type":"uint256"}],"name":"capUserBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currencyUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"freeMargins","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserFreeMargin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserPositions","outputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes12","name":"symbol","type":"bytes12"},{"internalType":"uint64","name":"margin","type":"uint64"},{"internalType":"uint64","name":"leverage","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint48","name":"block","type":"uint48"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"id","type":"uint256"}],"internalType":"struct Trading.Position[]","name":"_positions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_currency","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"positionIds","type":"uint256[]"}],"name":"liquidatePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"liquidatingIds","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidatorReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumMargin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"name":"pauseUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pausedUsers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes12","name":"symbol","type":"bytes12"},{"internalType":"uint64","name":"margin","type":"uint64"},{"internalType":"uint64","name":"leverage","type":"uint64"},{"internalType":"uint64","name":"price","type":"uint64"},{"internalType":"uint48","name":"block","type":"uint48"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"liquidator","type":"address"}],"name":"processOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_products","type":"address"},{"internalType":"address","name":"_queue","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"name":"registerContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setCurrencyMin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setLiquidatorReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"bytes32","name":"symbol","type":"bytes32"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"}],"name":"submitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"}],"name":"submitOrderUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"name":"unpauseUsers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50613159806100206000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80638456cb59116100f9578063b75fd83d11610097578063cc389d8611610071578063cc389d86146103a2578063d6bdf9e9146103aa578063e5a6b10f146103bd578063e9e441bb146103c5576101c4565b8063b75fd83d14610369578063ba537f811461037c578063c4d66de81461038f576101c4565b806399fbab88116100d357806399fbab88146103145780639e0db2a21461033b578063b10a821e1461034e578063b72db2b314610356576101c4565b80638456cb59146102e457806389e64630146102ec5780638da5cb5b146102ff576101c4565b80634d452ec011610166578063621a438511610140578063621a43851461029857806368d822c6146102ab5780636f609bdd146102be5780637e34dbe0146102d1576101c4565b80634d452ec01461026a5780635c975abb1461027d5780635f90734b14610285576101c4565b80632e1a7d4d116101a25780632e1a7d4d1461021c5780633a3da55a1461022f5780633e39a8be1461024f5780633f4ba83a14610262576101c4565b806305c0608c146101c957806319785225146101e75780632a6bc2dd146101fc575b600080fd5b6101d16103d8565b6040516101de9190612d19565b60405180910390f35b6101fa6101f536600461286e565b6103de565b005b61020f61020a3660046127e9565b61046a565b6040516101de9190612c3d565b6101fa61022a366004612977565b6105f3565b61024261023d366004612977565b610747565b6040516101de9190612d0e565b6101d161025d3660046127e9565b61075c565b6101fa61076e565b6101fa61027836600461286e565b6107a7565b61024261089b565b6101fa6102933660046129a7565b6108ab565b6101fa6102a63660046128ad565b610a6a565b6101d16102b93660046127e9565b610d91565b6101fa6102cc3660046129f7565b610dac565b6101fa6102df366004612aa6565b610eb1565b6101fa610feb565b6101fa6102fa36600461286e565b61102a565b6103076110a7565b6040516101de9190612b29565b610327610322366004612977565b6110b6565b6040516101de989796959493929190612bdc565b6101fa610349366004612845565b611128565b6101d161128b565b6101fa610364366004612803565b611291565b6101fa610377366004612977565b611339565b6101fa61038a366004612a18565b6113a3565b6101fa61039d3660046127e9565b611566565b6101d1611649565b6101d16103b83660046127e9565b61164f565b610307611661565b6101fa6103d3366004612977565b611670565b60045481565b600c546001600160a01b031633146104115760405162461bcd60e51b815260040161040890612f46565b60405180910390fd5b60005b81811015610465576000600a600085858581811061042e57fe5b905060200201602081019061044391906127e9565b6001600160a01b03168152602081019190915260400160002055600101610414565b505050565b6001600160a01b03811660009081526008602052604081206060919061048f906116f0565b9050806001600160401b03811180156104a757600080fd5b506040519080825280602002602001820160405280156104e157816020015b6104ce612746565b8152602001906001900390816104c65790505b50915060005b818110156105eb576001600160a01b038416600090815260086020526040812061051190836116f4565b905061051b612746565b5060008181526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b031916938201939093526001909101546001600160401b0380821694830194909452600160401b810484166060830152600160801b81049093166080820152600160c01b830465ffffffffffff1691810191909152600160f01b90910460ff16151560c082015260e08101829052845181908690859081106105d657fe5b602090810291909101015250506001016104e7565b50505b919050565b600c54600160a81b900460ff161561061d5760405162461bcd60e51b815260040161040890612e08565b336000818152600a60205260409020541561064a5760405162461bcd60e51b815260040161040890612ed4565b60408051808201825260088152672162616c616e636560c01b6020808301919091523360009081526006909152919091205461068791849061173a565b336000818152600660205260409020919091556002546005546001600160a01b0390911691633e458a8e916106bd908690611766565b6040518363ffffffff1660e01b81526004016106da929190612b3d565b600060405180830381600087803b1580156106f457600080fd5b505af1158015610708573d6000803e3d6000fd5b505050507fb6b476da71cea8275cac6b1720c04966afaff5e637472cedb6cbd32c43a232518260405161073b9190612d19565b60405180910390a15050565b60096020526000908152604090205460ff1681565b600a6020526000908152604090205481565b600c546001600160a01b031633146107985760405162461bcd60e51b815260040161040890612f46565b600c805460ff60a81b19169055565b80600681106107c85760405162461bcd60e51b815260040161040890612f6b565b60005b818110156108955760008484838181106107e157fe5b60209081029290920135600081815260079093526040909220600181015492935091600160801b90046001600160401b03161580159150610831575060008281526009602052604090205460ff16155b1561088b576000828152600960205260408120805460ff19166001908117909155820154825461088992600160f01b90920460ff1615916001600160a01b0319600160a01b90920460a01b9190911690808633611786565b505b50506001016107cb565b50505050565b600c54600160a81b900460ff1681565b600c54600160a81b900460ff16156108d55760405162461bcd60e51b815260040161040890612e08565b6001546001600160a01b031633146108ff5760405162461bcd60e51b815260040161040890612f46565b8115610a57576001600160a01b03811615610a47576000828152600960205260409020805460ff19169055610932612746565b5060008281526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b0319169382019390935260018201546001600160401b0380821695830195909552600160401b810485166060830152600160801b810490941660808201819052600160c01b850465ffffffffffff1693820193909352600160f01b90930460ff16151560c08401526002015460e08301526109fc5760405162461bcd60e51b815260040161040890612ffa565b60408101516001600160401b0316600080610a1884848a6118be565b91509150808015610a295750828210155b15610a3e57610a3e8587858760000151611ab5565b50505050610a52565b610a52838584611c18565b610a62565b610a62868686612064565b505050505050565b600c54600160a81b900460ff1615610a945760405162461bcd60e51b815260040161040890612e08565b336000818152600a602052604090205415610ac15760405162461bcd60e51b815260040161040890612ed4565b600454831015610ae35760405162461bcd60e51b815260040161040890612eb3565b6305f5e100821015610b075760405162461bcd60e51b815260040161040890612ef9565b6000805460405163188cac2d60e31b81526001600160a01b039091169063c465616890610b3b908890600190600401612d22565b60206040518083038186803b158015610b5357600080fd5b505afa158015610b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8b919061298f565b905060008111610bad5760405162461bcd60e51b81526004016104089061301a565b80831115610bcd5760405162461bcd60e51b815260040161040890612e6a565b60408051808201825260088152672162616c616e636560c01b60208083019190915233600090815260069091529190912054610c0a91869061173a565b33600090815260066020526040812091909155610c2b878787878580611786565b6040805161010081018252338152600060208201529192508101610c4e8761222d565b6001600160401b03168152602001610c658661222d565b6001600160401b0390811682526000602080840182905260408085018390529b1515606080860191909152608094850183905295825260078152908b902084518154928601516001600160a01b03199093166001600160a01b039182161716600160a01b60a093841c021781559a84015160018c01805496860151948601519286015160c087015167ffffffffffffffff19909816928516929092176fffffffffffffffff00000000000000001916600160401b958516959095029490941767ffffffffffffffff60801b1916600160801b92909316919091029190911765ffffffffffff60c01b1916600160c01b65ffffffffffff909216919091021760ff60f01b1916600160f01b931515939093029290921790915560e001516002909601959095555050505050565b6001600160a01b031660009081526006602052604090205490565b600c54600160a81b900460ff1615610dd65760405162461bcd60e51b815260040161040890612e08565b60008281526007602052604090206001810154600160801b90046001600160401b0316610e155760405162461bcd60e51b815260040161040890612ffa565b80546001600160a01b03163314610e3e5760405162461bcd60e51b815260040161040890612f46565b60018101546001600160401b0316821115610e6b5760405162461bcd60e51b815260040161040890612eb3565b6001810154815461089591600160f01b810460ff161591600160a01b900460a01b6001600160a01b031916908590600160401b90046001600160401b0316876000611786565b600c54600160a81b900460ff1615610edb5760405162461bcd60e51b815260040161040890612e08565b6000610ef26005548761176690919063ffffffff16565b600354600254919250610f19916001600160a01b039182169184913391168989898961225a565b60025460405163b52d734360e01b81526001600160a01b039091169063b52d734390610f4b9033908590600401612b3d565b600060405180830381600087803b158015610f6557600080fd5b505af1158015610f79573d6000803e3d6000fd5b505033600090815260066020526040902054610f98925090508761247e565b336000908152600660205260409081902091909155517f2a89b2e3d580398d6dc2db5e0f336b52602bbaa51afa9bb5cdf59239cf0d2bea90610fdb908890612d19565b60405180910390a1505050505050565b600c546001600160a01b031633146110155760405162461bcd60e51b815260040161040890612f46565b600c805460ff60a81b1916600160a81b179055565b600c546001600160a01b031633146110545760405162461bcd60e51b815260040161040890612f46565b60005b818110156104655743600a600085858581811061107057fe5b905060200201602081019061108591906127e9565b6001600160a01b03168152602081019190915260400160002055600101611057565b600c546001600160a01b031681565b6007602052600090815260409020805460018201546002909201546001600160a01b03821692600160a01b90920460a01b916001600160401b0380821692600160401b8304821692600160801b810490921691600160c01b810465ffffffffffff1691600160f01b90910460ff169088565b600c546001600160a01b031633146111525760405162461bcd60e51b815260040161040890612f46565b6001600160a01b0382166000908152600a6020526040902054801580159061117957504381105b6111955760405162461bcd60e51b815260040161040890612f1c565b6002546040516323b9a44960e11b81526000916001600160a01b0316906347734892906111c6908790600401612b29565b60206040518083038186803b1580156111de57600080fd5b505afa1580156111f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611216919061298f565b90508061122e6005548561176690919063ffffffff16565b101561124c5760405162461bcd60e51b815260040161040890612e91565b6001600160a01b0384166000908152600660205260409020548310156108955750506001600160a01b0391909116600090815260066020526040902055565b600b5481565b600c546001600160a01b031633146112bb5760405162461bcd60e51b815260040161040890612f46565b600080546001600160a01b038086166001600160a01b0319928316179092556001805485841690831617905560028054928416929091169190911790556040517fab89ae7c33202f499ee63ff28e56285c9c67716e8a6fdcbcce8f73bfadd6b2439061132c90859085908590612b70565b60405180910390a1505050565b600c546001600160a01b031633146113635760405162461bcd60e51b815260040161040890612f46565b60048190556040517f334b167d1f7f5e3c74a46551e4002af2b3b38d53072d67aa67e691f43591687b90611398908390612d19565b60405180910390a150565b6001546001600160a01b031633146113cd5760405162461bcd60e51b815260040161040890612f46565b8361149357600085815260076020908152604080832080546001820180548684556001600160f81b03198116909155600283018690556001600160a01b03909116808652600690945291909320546001600160401b0390911690611431908261247e565b6001600160a01b038316600081815260066020526040908190209290925590517ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce390611483908b9081908a908a90613071565b60405180910390a250505061155f565b6001600160a01b038316156115055760008581526009602052604090819020805460ff19169055516001600160a01b038416907ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce3906114f8908890889087908790613071565b60405180910390a261155f565b600084815260076020526040908190205490516001600160a01b03909116907ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce390611556908890889087908790613071565b60405180910390a25b5050505050565b600c54600160a01b900460ff16156115905760405162461bcd60e51b815260040161040890612d89565b600c80546001600160a01b031960ff60a01b19909116600160a01b1781163317909155600a600b55600380546001600160a01b0384169216821790556040805163313ce56760e01b81529051611643929163313ce567916004808301926020929190829003018186803b15801561160657600080fd5b505afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190612aee565b6124aa565b60055550565b60055481565b60066020526000908152604090205481565b6003546001600160a01b031681565b600c546001600160a01b0316331461169a5760405162461bcd60e51b815260040161040890612f46565b60648111156116bb5760405162461bcd60e51b815260040161040890612daf565b600b8190556040517f234f84cb45c3f3ae398218c31d7e8bf5f31b037e05fc5961d3569f4fa6616d7c90611398908390612d19565b5490565b815460009082106117175760405162461bcd60e51b815260040161040890612fc5565b82600001828154811061172657fe5b906000526020600020015490505b92915050565b6000818484111561175e5760405162461bcd60e51b81526004016104089190612d56565b505050900390565b60006305f5e1006117778484612529565b8161177e57fe5b049392505050565b60015460405163332463ad60e21b81526000916001600160a01b03169063cc918eb4906117bd908990899088908890600401612d32565b602060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180f919061298f565b90506001600160a01b0382161561186857336001600160a01b03167f15c7da4af2133090a14dba8b02646e4d2ded2b9e8173addcd1b8d42719635112828560405161185b929190613063565b60405180910390a26118b4565b336001600160a01b03167f383af269d455c7ea93aa547244a2d345d395985c71392361c9e08b134826a65d8289898989896040516118ab9695949392919061303b565b60405180910390a25b9695505050505050565b600080600085606001516001600160401b03169050600086608001516001600160401b031690508660c001511561195a5786608001516001600160401b03168510611937576119306305f5e10061192a838161191a8a83612563565b6119248c89612529565b90612529565b906125a5565b9350611955565b61194e6305f5e10061192a838161191a828b612563565b9350600192505b6119a0565b86608001516001600160401b03168511156119865761194e6305f5e10061192a838161191a8a83612563565b61199d6305f5e10061192a838161191a828b612563565b93505b6000805460208901516040516384f6e7b360e01b8152611a6e92662386f26fc100009261192a926001600160a01b03909216916384f6e7b3916119f2916001600160a01b031990911690600401612d19565b60206040518083038186803b158015611a0a57600080fd5b505afa158015611a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a42919061298f565b611924611a648d60a0015165ffffffffffff164361256390919063ffffffff16565b6119248d8a612529565b90508315611a8757611a80858261247e565b9450611aaa565b84811115611a9d5760019350611a808186612563565b611aa78582612563565b94505b505050935093915050565b60008381526007602090815260408083208381556001810180546001600160f81b03191690556002018390556001600160a01b038416835260089091529020611afe90846125e7565b506002546005546001600160a01b039091169063b5c20dd3908390611b24908690611766565b6040518363ffffffff1660e01b8152600401611b41929190612b3d565b600060405180830381600087803b158015611b5b57600080fd5b505af1158015611b6f573d6000803e3d6000fd5b505050506000611b8f606461192a600b548661252990919063ffffffff16565b6001600160a01b038616600090815260066020526040902054909150611bb5908261247e565b6001600160a01b0380871660008181526006602052604090819020939093559151908416907f9f843df2e2b0c791e0c3993c883e11d06a6fcc960fb3a2765a6f4ab8a1bd07ca90611c099088908890613063565b60405180910390a35050505050565b611c20612746565b5060008181526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b0319169382019390935260018201546001600160401b03808216958301869052600160401b820481166060840152600160801b8204166080830152600160c01b810465ffffffffffff1693820193909352600160f01b90920460ff16151560c08301526002015460e08201529080851115611cea5760405162461bcd60e51b815260040161040890612eb3565b60008054602084015160405163443182fd60e01b81526001600160a01b039092169163443182fd91611d2b916001600160a01b031990911690600401612d19565b60206040518083038186803b158015611d4357600080fd5b505afa158015611d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7b919061298f565b90508260c0015115611da657611d9f611d986305f5e10083612563565b8690611766565b9450611dba565b611db7611d986305f5e1008361247e565b94505b600080611dc88589896118be565b915091506000818015611ddb5750888310155b15611ea55760008781526007602090815260408083208381556001810180546001600160f81b031916905560020183905588516001600160a01b0316835260089091529020611e2a90886125e7565b5060025486516005546001600160a01b039092169163b5c20dd39190611e51908990611766565b6040518363ffffffff1660e01b8152600401611e6e929190612b3d565b600060405180830381600087803b158015611e8857600080fd5b505af1158015611e9c573d6000803e3d6000fd5b50505050612002565b84891015611ef6576000878152600760205260409020611ecd611ec8878c612563565b61222d565b600191909101805467ffffffffffffffff19166001600160401b03909216919091179055611f42565b60008781526007602090815260408083208381556001810180546001600160f81b031916905560020183905588516001600160a01b0316835260089091529020611f4090886125e7565b505b8115611fb657611f528984612563565b86516001600160a01b0316600090815260066020526040902054909150611f79908261247e565b86516001600160a01b039081166000908152600660205260409020919091556002548751600554919092169163b5c20dd391611e51908790611766565b611fc0898461247e565b86516001600160a01b0316600090815260066020526040902054909150611fe7908261247e565b86516001600160a01b03166000908152600660205260409020555b85600001516001600160a01b03167fb740da1ca3b7364c36886a66a0a5a33c31a8985a91673f3bc2ae6ae876007657888b848a608001518d8c60600151604051612051969594939291906130ae565b60405180910390a2505050505050505050565b600083815260076020526040808220600181015481548454935163443182fd60e01b81529294600160f01b830460ff16946001600160401b0380851695600160401b90950416936001600160a01b03938416939091169063443182fd906120cf908b90600401612d19565b60206040518083038186803b1580156120e757600080fd5b505afa1580156120fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211f919061298f565b905084156121465761213f6121386305f5e1008361247e565b8890611766565b965061215a565b6121576121386305f5e10083612563565b96505b85546001600160a01b0316600160a01b60a08a901c0217865561217c8761222d565b60018701805467ffffffffffffffff60801b1916600160801b6001600160401b0393909316929092029190911765ffffffffffff60c01b1916600160c01b4365ffffffffffff16021790556001600160a01b03821660009081526008602052604090206121e9908a6126ad565b50816001600160a01b03167f94046b799d1f5befe29f320688602f36227b2884ebbfa15c12ad25f6aede27c58a878b88888d6040516120519695949392919061303b565b60006001600160401b038211156122565760405162461bcd60e51b815260040161040890612f8e565b5090565b604051636eb1769f60e11b815287906001600160a01b038a169063dd62ed3e9061228a908a908a90600401612b56565b60206040518083038186803b1580156122a257600080fd5b505afa1580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da919061298f565b101561247457876001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561231957600080fd5b505afa15801561232d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261235591908101906128eb565b80516020909101207fa5e92f3efb6826155f1f728e162af9d7cda33a574a1153b58f03ea01cc37e568141561247457604051623f675f60e91b81526000906001600160a01b038a1690637ecebe00906123b2908a90600401612b29565b60206040518083038186803b1580156123ca57600080fd5b505afa1580156123de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612402919061298f565b6040516323f2ebc360e21b81529091506001600160a01b038a1690638fcbaf0c90612440908a908a9086908b906001908c908c908c90600401612b93565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b50505050505b5050505050505050565b6000828201838110156124a35760405162461bcd60e51b815260040161040890612dd1565b9392505050565b60008160ff16601214156124c75750670de0b6b3a76400006105ee565b8160ff16600614156124dd5750620f42406105ee565b60015b600a8360ff1610612507576124fa816402540be400612529565b9050600a830392506124e0565b60ff8316156117345761251b81600a612529565b600019909301929050612507565b60008261253857506000611734565b8282028284828161254557fe5b04146124a35760405162461bcd60e51b815260040161040890612e29565b60006124a383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061173a565b60006124a383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126f7565b600081815260018301602052604081205480156126a3578354600019808301919081019060009087908390811061261a57fe5b906000526020600020015490508087600001848154811061263757fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061266757fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611734565b6000915050611734565b60006126b9838361272e565b6126ef57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611734565b506000611734565b600081836127185760405162461bcd60e51b81526004016104089190612d56565b50600083858161272457fe5b0495945050505050565b60009081526001919091016020526040902054151590565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b80356001600160a01b03811681146105ee57600080fd5b60008083601f8401126127b2578182fd5b5081356001600160401b038111156127c8578182fd5b60208301915083602080830285010111156127e257600080fd5b9250929050565b6000602082840312156127fa578081fd5b6124a38261278a565b600080600060608486031215612817578182fd5b6128208461278a565b925061282e6020850161278a565b915061283c6040850161278a565b90509250925092565b60008060408385031215612857578182fd5b6128608361278a565b946020939093013593505050565b60008060208385031215612880578182fd5b82356001600160401b03811115612895578283fd5b6128a1858286016127a1565b90969095509350505050565b600080600080608085870312156128c2578081fd5b843580151581146128d1578182fd5b966020860135965060408601359560600135945092505050565b6000602082840312156128fc578081fd5b81516001600160401b0380821115612912578283fd5b818401915084601f830112612925578283fd5b81518181111561293157fe5b604051601f8201601f19168101602001838111828210171561294f57fe5b604052818152838201602001871015612966578485fd5b6118b48260208301602087016130e5565b600060208284031215612988578081fd5b5035919050565b6000602082840312156129a0578081fd5b5051919050565b60008060008060008060c087890312156129bf578182fd5b86359550602087013594506040870135935060608701359250608087013591506129eb60a0880161278a565b90509295509295509295565b60008060408385031215612a09578182fd5b50508035926020909101359150565b600080600080600060808688031215612a2f578081fd5b8535945060208601359350612a466040870161278a565b925060608601356001600160401b0380821115612a61578283fd5b818801915088601f830112612a74578283fd5b813581811115612a82578384fd5b896020828501011115612a93578384fd5b9699959850939650602001949392505050565b600080600080600060a08688031215612abd578283fd5b85359450602086013593506040860135612ad681613111565b94979396509394606081013594506080013592915050565b600060208284031215612aff578081fd5b81516124a381613111565b15159052565b65ffffffffffff169052565b6001600160401b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039889168152969097166020870152604086019490945260608501929092521515608084015260ff1660a083015260c082015260e08101919091526101000190565b6001600160a01b039890981688526001600160a01b03199690961660208801526001600160401b03948516604088015292841660608701529216608085015265ffffffffffff90911660a0840152151560c083015260e08201526101000190565b602080825282518282018190526000919060409081850190868401855b82811015612d0157815180516001600160a01b03168552868101516001600160a01b03191687860152858101516001600160401b031686860152606080820151612ca682880182612b1c565b5050608080820151612cba82880182612b1c565b505060a080820151612cce82880182612b10565b505060c080820151612ce282880182612b0a565b505060e090810151908501526101009093019290850190600101612c5a565b5091979650505050505050565b901515815260200190565b90815260200190565b9182521515602082015260400190565b938452602084019290925260408301526001600160a01b0316606082015260800190565b6000602082528251806020840152612d758160408501602087016130e5565b601f01601f19169190910160400192915050565b6020808252600c908201526b085a5b9a5d1a585b1a5e995960a21b604082015260600190565b602080825260089082015267085c195c98d95b9d60c21b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b602080825260079082015266085c185d5cd95960ca1b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600d908201526c216d61785f6c6576657261676560981b604082015260600190565b60208082526008908201526721746f6f5f6c6f7760c01b604082015260600190565b60208082526007908201526610b6b0b933b4b760c91b604082015260600190565b6020808252600b908201526a10b830bab9b2b22ab9b2b960a91b604082015260600190565b602080825260099082015268216c6576657261676560b81b604082015260600190565b60208082526010908201526f085d5cd95c97db9bdd17dc185d5cd95960821b604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b60208082526009908201526821746f6f5f6d616e7960b81b604082015260600190565b60208082526017908201527f536166654d6174683a2063617374206f766572666c6f77000000000000000000604082015260600190565b6020808252818101527f55696e74456e756d657261626c655365743a204f55545f4f465f424f554e4453604082015260600190565b60208082526006908201526508599bdd5b9960d21b604082015260600190565b602080825260079082015266085cde5b589bdb60ca1b604082015260600190565b958652931515602086015260408501929092526060840152608083015260a082015260c00190565b918252602082015260400190565b60008582528460208301526060604083015282606083015282846080840137818301608090810191909152601f909201601f191601019392505050565b958652602086019490945260408501929092526001600160401b03908116606085015260808401919091521660a082015260c00190565b60005b838110156131005781810151838201526020016130e8565b838111156108955750506000910152565b60ff8116811461312057600080fd5b5056fea2646970667358221220a90a35f9a76195efe9dffbde0f321e645ef3f8aef0745e67fbbe75a7a19ea28b64736f6c63430007030033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80638456cb59116100f9578063b75fd83d11610097578063cc389d8611610071578063cc389d86146103a2578063d6bdf9e9146103aa578063e5a6b10f146103bd578063e9e441bb146103c5576101c4565b8063b75fd83d14610369578063ba537f811461037c578063c4d66de81461038f576101c4565b806399fbab88116100d357806399fbab88146103145780639e0db2a21461033b578063b10a821e1461034e578063b72db2b314610356576101c4565b80638456cb59146102e457806389e64630146102ec5780638da5cb5b146102ff576101c4565b80634d452ec011610166578063621a438511610140578063621a43851461029857806368d822c6146102ab5780636f609bdd146102be5780637e34dbe0146102d1576101c4565b80634d452ec01461026a5780635c975abb1461027d5780635f90734b14610285576101c4565b80632e1a7d4d116101a25780632e1a7d4d1461021c5780633a3da55a1461022f5780633e39a8be1461024f5780633f4ba83a14610262576101c4565b806305c0608c146101c957806319785225146101e75780632a6bc2dd146101fc575b600080fd5b6101d16103d8565b6040516101de9190612d19565b60405180910390f35b6101fa6101f536600461286e565b6103de565b005b61020f61020a3660046127e9565b61046a565b6040516101de9190612c3d565b6101fa61022a366004612977565b6105f3565b61024261023d366004612977565b610747565b6040516101de9190612d0e565b6101d161025d3660046127e9565b61075c565b6101fa61076e565b6101fa61027836600461286e565b6107a7565b61024261089b565b6101fa6102933660046129a7565b6108ab565b6101fa6102a63660046128ad565b610a6a565b6101d16102b93660046127e9565b610d91565b6101fa6102cc3660046129f7565b610dac565b6101fa6102df366004612aa6565b610eb1565b6101fa610feb565b6101fa6102fa36600461286e565b61102a565b6103076110a7565b6040516101de9190612b29565b610327610322366004612977565b6110b6565b6040516101de989796959493929190612bdc565b6101fa610349366004612845565b611128565b6101d161128b565b6101fa610364366004612803565b611291565b6101fa610377366004612977565b611339565b6101fa61038a366004612a18565b6113a3565b6101fa61039d3660046127e9565b611566565b6101d1611649565b6101d16103b83660046127e9565b61164f565b610307611661565b6101fa6103d3366004612977565b611670565b60045481565b600c546001600160a01b031633146104115760405162461bcd60e51b815260040161040890612f46565b60405180910390fd5b60005b81811015610465576000600a600085858581811061042e57fe5b905060200201602081019061044391906127e9565b6001600160a01b03168152602081019190915260400160002055600101610414565b505050565b6001600160a01b03811660009081526008602052604081206060919061048f906116f0565b9050806001600160401b03811180156104a757600080fd5b506040519080825280602002602001820160405280156104e157816020015b6104ce612746565b8152602001906001900390816104c65790505b50915060005b818110156105eb576001600160a01b038416600090815260086020526040812061051190836116f4565b905061051b612746565b5060008181526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b031916938201939093526001909101546001600160401b0380821694830194909452600160401b810484166060830152600160801b81049093166080820152600160c01b830465ffffffffffff1691810191909152600160f01b90910460ff16151560c082015260e08101829052845181908690859081106105d657fe5b602090810291909101015250506001016104e7565b50505b919050565b600c54600160a81b900460ff161561061d5760405162461bcd60e51b815260040161040890612e08565b336000818152600a60205260409020541561064a5760405162461bcd60e51b815260040161040890612ed4565b60408051808201825260088152672162616c616e636560c01b6020808301919091523360009081526006909152919091205461068791849061173a565b336000818152600660205260409020919091556002546005546001600160a01b0390911691633e458a8e916106bd908690611766565b6040518363ffffffff1660e01b81526004016106da929190612b3d565b600060405180830381600087803b1580156106f457600080fd5b505af1158015610708573d6000803e3d6000fd5b505050507fb6b476da71cea8275cac6b1720c04966afaff5e637472cedb6cbd32c43a232518260405161073b9190612d19565b60405180910390a15050565b60096020526000908152604090205460ff1681565b600a6020526000908152604090205481565b600c546001600160a01b031633146107985760405162461bcd60e51b815260040161040890612f46565b600c805460ff60a81b19169055565b80600681106107c85760405162461bcd60e51b815260040161040890612f6b565b60005b818110156108955760008484838181106107e157fe5b60209081029290920135600081815260079093526040909220600181015492935091600160801b90046001600160401b03161580159150610831575060008281526009602052604090205460ff16155b1561088b576000828152600960205260408120805460ff19166001908117909155820154825461088992600160f01b90920460ff1615916001600160a01b0319600160a01b90920460a01b9190911690808633611786565b505b50506001016107cb565b50505050565b600c54600160a81b900460ff1681565b600c54600160a81b900460ff16156108d55760405162461bcd60e51b815260040161040890612e08565b6001546001600160a01b031633146108ff5760405162461bcd60e51b815260040161040890612f46565b8115610a57576001600160a01b03811615610a47576000828152600960205260409020805460ff19169055610932612746565b5060008281526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b0319169382019390935260018201546001600160401b0380821695830195909552600160401b810485166060830152600160801b810490941660808201819052600160c01b850465ffffffffffff1693820193909352600160f01b90930460ff16151560c08401526002015460e08301526109fc5760405162461bcd60e51b815260040161040890612ffa565b60408101516001600160401b0316600080610a1884848a6118be565b91509150808015610a295750828210155b15610a3e57610a3e8587858760000151611ab5565b50505050610a52565b610a52838584611c18565b610a62565b610a62868686612064565b505050505050565b600c54600160a81b900460ff1615610a945760405162461bcd60e51b815260040161040890612e08565b336000818152600a602052604090205415610ac15760405162461bcd60e51b815260040161040890612ed4565b600454831015610ae35760405162461bcd60e51b815260040161040890612eb3565b6305f5e100821015610b075760405162461bcd60e51b815260040161040890612ef9565b6000805460405163188cac2d60e31b81526001600160a01b039091169063c465616890610b3b908890600190600401612d22565b60206040518083038186803b158015610b5357600080fd5b505afa158015610b67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8b919061298f565b905060008111610bad5760405162461bcd60e51b81526004016104089061301a565b80831115610bcd5760405162461bcd60e51b815260040161040890612e6a565b60408051808201825260088152672162616c616e636560c01b60208083019190915233600090815260069091529190912054610c0a91869061173a565b33600090815260066020526040812091909155610c2b878787878580611786565b6040805161010081018252338152600060208201529192508101610c4e8761222d565b6001600160401b03168152602001610c658661222d565b6001600160401b0390811682526000602080840182905260408085018390529b1515606080860191909152608094850183905295825260078152908b902084518154928601516001600160a01b03199093166001600160a01b039182161716600160a01b60a093841c021781559a84015160018c01805496860151948601519286015160c087015167ffffffffffffffff19909816928516929092176fffffffffffffffff00000000000000001916600160401b958516959095029490941767ffffffffffffffff60801b1916600160801b92909316919091029190911765ffffffffffff60c01b1916600160c01b65ffffffffffff909216919091021760ff60f01b1916600160f01b931515939093029290921790915560e001516002909601959095555050505050565b6001600160a01b031660009081526006602052604090205490565b600c54600160a81b900460ff1615610dd65760405162461bcd60e51b815260040161040890612e08565b60008281526007602052604090206001810154600160801b90046001600160401b0316610e155760405162461bcd60e51b815260040161040890612ffa565b80546001600160a01b03163314610e3e5760405162461bcd60e51b815260040161040890612f46565b60018101546001600160401b0316821115610e6b5760405162461bcd60e51b815260040161040890612eb3565b6001810154815461089591600160f01b810460ff161591600160a01b900460a01b6001600160a01b031916908590600160401b90046001600160401b0316876000611786565b600c54600160a81b900460ff1615610edb5760405162461bcd60e51b815260040161040890612e08565b6000610ef26005548761176690919063ffffffff16565b600354600254919250610f19916001600160a01b039182169184913391168989898961225a565b60025460405163b52d734360e01b81526001600160a01b039091169063b52d734390610f4b9033908590600401612b3d565b600060405180830381600087803b158015610f6557600080fd5b505af1158015610f79573d6000803e3d6000fd5b505033600090815260066020526040902054610f98925090508761247e565b336000908152600660205260409081902091909155517f2a89b2e3d580398d6dc2db5e0f336b52602bbaa51afa9bb5cdf59239cf0d2bea90610fdb908890612d19565b60405180910390a1505050505050565b600c546001600160a01b031633146110155760405162461bcd60e51b815260040161040890612f46565b600c805460ff60a81b1916600160a81b179055565b600c546001600160a01b031633146110545760405162461bcd60e51b815260040161040890612f46565b60005b818110156104655743600a600085858581811061107057fe5b905060200201602081019061108591906127e9565b6001600160a01b03168152602081019190915260400160002055600101611057565b600c546001600160a01b031681565b6007602052600090815260409020805460018201546002909201546001600160a01b03821692600160a01b90920460a01b916001600160401b0380821692600160401b8304821692600160801b810490921691600160c01b810465ffffffffffff1691600160f01b90910460ff169088565b600c546001600160a01b031633146111525760405162461bcd60e51b815260040161040890612f46565b6001600160a01b0382166000908152600a6020526040902054801580159061117957504381105b6111955760405162461bcd60e51b815260040161040890612f1c565b6002546040516323b9a44960e11b81526000916001600160a01b0316906347734892906111c6908790600401612b29565b60206040518083038186803b1580156111de57600080fd5b505afa1580156111f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611216919061298f565b90508061122e6005548561176690919063ffffffff16565b101561124c5760405162461bcd60e51b815260040161040890612e91565b6001600160a01b0384166000908152600660205260409020548310156108955750506001600160a01b0391909116600090815260066020526040902055565b600b5481565b600c546001600160a01b031633146112bb5760405162461bcd60e51b815260040161040890612f46565b600080546001600160a01b038086166001600160a01b0319928316179092556001805485841690831617905560028054928416929091169190911790556040517fab89ae7c33202f499ee63ff28e56285c9c67716e8a6fdcbcce8f73bfadd6b2439061132c90859085908590612b70565b60405180910390a1505050565b600c546001600160a01b031633146113635760405162461bcd60e51b815260040161040890612f46565b60048190556040517f334b167d1f7f5e3c74a46551e4002af2b3b38d53072d67aa67e691f43591687b90611398908390612d19565b60405180910390a150565b6001546001600160a01b031633146113cd5760405162461bcd60e51b815260040161040890612f46565b8361149357600085815260076020908152604080832080546001820180548684556001600160f81b03198116909155600283018690556001600160a01b03909116808652600690945291909320546001600160401b0390911690611431908261247e565b6001600160a01b038316600081815260066020526040908190209290925590517ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce390611483908b9081908a908a90613071565b60405180910390a250505061155f565b6001600160a01b038316156115055760008581526009602052604090819020805460ff19169055516001600160a01b038416907ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce3906114f8908890889087908790613071565b60405180910390a261155f565b600084815260076020526040908190205490516001600160a01b03909116907ef7bcdad0753e20ba80e87c6efe2385dd122fae77e6219e92368c4ba0cd7ce390611556908890889087908790613071565b60405180910390a25b5050505050565b600c54600160a01b900460ff16156115905760405162461bcd60e51b815260040161040890612d89565b600c80546001600160a01b031960ff60a01b19909116600160a01b1781163317909155600a600b55600380546001600160a01b0384169216821790556040805163313ce56760e01b81529051611643929163313ce567916004808301926020929190829003018186803b15801561160657600080fd5b505afa15801561161a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163e9190612aee565b6124aa565b60055550565b60055481565b60066020526000908152604090205481565b6003546001600160a01b031681565b600c546001600160a01b0316331461169a5760405162461bcd60e51b815260040161040890612f46565b60648111156116bb5760405162461bcd60e51b815260040161040890612daf565b600b8190556040517f234f84cb45c3f3ae398218c31d7e8bf5f31b037e05fc5961d3569f4fa6616d7c90611398908390612d19565b5490565b815460009082106117175760405162461bcd60e51b815260040161040890612fc5565b82600001828154811061172657fe5b906000526020600020015490505b92915050565b6000818484111561175e5760405162461bcd60e51b81526004016104089190612d56565b505050900390565b60006305f5e1006117778484612529565b8161177e57fe5b049392505050565b60015460405163332463ad60e21b81526000916001600160a01b03169063cc918eb4906117bd908990899088908890600401612d32565b602060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180f919061298f565b90506001600160a01b0382161561186857336001600160a01b03167f15c7da4af2133090a14dba8b02646e4d2ded2b9e8173addcd1b8d42719635112828560405161185b929190613063565b60405180910390a26118b4565b336001600160a01b03167f383af269d455c7ea93aa547244a2d345d395985c71392361c9e08b134826a65d8289898989896040516118ab9695949392919061303b565b60405180910390a25b9695505050505050565b600080600085606001516001600160401b03169050600086608001516001600160401b031690508660c001511561195a5786608001516001600160401b03168510611937576119306305f5e10061192a838161191a8a83612563565b6119248c89612529565b90612529565b906125a5565b9350611955565b61194e6305f5e10061192a838161191a828b612563565b9350600192505b6119a0565b86608001516001600160401b03168511156119865761194e6305f5e10061192a838161191a8a83612563565b61199d6305f5e10061192a838161191a828b612563565b93505b6000805460208901516040516384f6e7b360e01b8152611a6e92662386f26fc100009261192a926001600160a01b03909216916384f6e7b3916119f2916001600160a01b031990911690600401612d19565b60206040518083038186803b158015611a0a57600080fd5b505afa158015611a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a42919061298f565b611924611a648d60a0015165ffffffffffff164361256390919063ffffffff16565b6119248d8a612529565b90508315611a8757611a80858261247e565b9450611aaa565b84811115611a9d5760019350611a808186612563565b611aa78582612563565b94505b505050935093915050565b60008381526007602090815260408083208381556001810180546001600160f81b03191690556002018390556001600160a01b038416835260089091529020611afe90846125e7565b506002546005546001600160a01b039091169063b5c20dd3908390611b24908690611766565b6040518363ffffffff1660e01b8152600401611b41929190612b3d565b600060405180830381600087803b158015611b5b57600080fd5b505af1158015611b6f573d6000803e3d6000fd5b505050506000611b8f606461192a600b548661252990919063ffffffff16565b6001600160a01b038616600090815260066020526040902054909150611bb5908261247e565b6001600160a01b0380871660008181526006602052604090819020939093559151908416907f9f843df2e2b0c791e0c3993c883e11d06a6fcc960fb3a2765a6f4ab8a1bd07ca90611c099088908890613063565b60405180910390a35050505050565b611c20612746565b5060008181526007602090815260409182902082516101008101845281546001600160a01b0381168252600160a01b900460a090811b6001600160a01b0319169382019390935260018201546001600160401b03808216958301869052600160401b820481166060840152600160801b8204166080830152600160c01b810465ffffffffffff1693820193909352600160f01b90920460ff16151560c08301526002015460e08201529080851115611cea5760405162461bcd60e51b815260040161040890612eb3565b60008054602084015160405163443182fd60e01b81526001600160a01b039092169163443182fd91611d2b916001600160a01b031990911690600401612d19565b60206040518083038186803b158015611d4357600080fd5b505afa158015611d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7b919061298f565b90508260c0015115611da657611d9f611d986305f5e10083612563565b8690611766565b9450611dba565b611db7611d986305f5e1008361247e565b94505b600080611dc88589896118be565b915091506000818015611ddb5750888310155b15611ea55760008781526007602090815260408083208381556001810180546001600160f81b031916905560020183905588516001600160a01b0316835260089091529020611e2a90886125e7565b5060025486516005546001600160a01b039092169163b5c20dd39190611e51908990611766565b6040518363ffffffff1660e01b8152600401611e6e929190612b3d565b600060405180830381600087803b158015611e8857600080fd5b505af1158015611e9c573d6000803e3d6000fd5b50505050612002565b84891015611ef6576000878152600760205260409020611ecd611ec8878c612563565b61222d565b600191909101805467ffffffffffffffff19166001600160401b03909216919091179055611f42565b60008781526007602090815260408083208381556001810180546001600160f81b031916905560020183905588516001600160a01b0316835260089091529020611f4090886125e7565b505b8115611fb657611f528984612563565b86516001600160a01b0316600090815260066020526040902054909150611f79908261247e565b86516001600160a01b039081166000908152600660205260409020919091556002548751600554919092169163b5c20dd391611e51908790611766565b611fc0898461247e565b86516001600160a01b0316600090815260066020526040902054909150611fe7908261247e565b86516001600160a01b03166000908152600660205260409020555b85600001516001600160a01b03167fb740da1ca3b7364c36886a66a0a5a33c31a8985a91673f3bc2ae6ae876007657888b848a608001518d8c60600151604051612051969594939291906130ae565b60405180910390a2505050505050505050565b600083815260076020526040808220600181015481548454935163443182fd60e01b81529294600160f01b830460ff16946001600160401b0380851695600160401b90950416936001600160a01b03938416939091169063443182fd906120cf908b90600401612d19565b60206040518083038186803b1580156120e757600080fd5b505afa1580156120fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211f919061298f565b905084156121465761213f6121386305f5e1008361247e565b8890611766565b965061215a565b6121576121386305f5e10083612563565b96505b85546001600160a01b0316600160a01b60a08a901c0217865561217c8761222d565b60018701805467ffffffffffffffff60801b1916600160801b6001600160401b0393909316929092029190911765ffffffffffff60c01b1916600160c01b4365ffffffffffff16021790556001600160a01b03821660009081526008602052604090206121e9908a6126ad565b50816001600160a01b03167f94046b799d1f5befe29f320688602f36227b2884ebbfa15c12ad25f6aede27c58a878b88888d6040516120519695949392919061303b565b60006001600160401b038211156122565760405162461bcd60e51b815260040161040890612f8e565b5090565b604051636eb1769f60e11b815287906001600160a01b038a169063dd62ed3e9061228a908a908a90600401612b56565b60206040518083038186803b1580156122a257600080fd5b505afa1580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da919061298f565b101561247457876001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561231957600080fd5b505afa15801561232d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261235591908101906128eb565b80516020909101207fa5e92f3efb6826155f1f728e162af9d7cda33a574a1153b58f03ea01cc37e568141561247457604051623f675f60e91b81526000906001600160a01b038a1690637ecebe00906123b2908a90600401612b29565b60206040518083038186803b1580156123ca57600080fd5b505afa1580156123de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612402919061298f565b6040516323f2ebc360e21b81529091506001600160a01b038a1690638fcbaf0c90612440908a908a9086908b906001908c908c908c90600401612b93565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b50505050505b5050505050505050565b6000828201838110156124a35760405162461bcd60e51b815260040161040890612dd1565b9392505050565b60008160ff16601214156124c75750670de0b6b3a76400006105ee565b8160ff16600614156124dd5750620f42406105ee565b60015b600a8360ff1610612507576124fa816402540be400612529565b9050600a830392506124e0565b60ff8316156117345761251b81600a612529565b600019909301929050612507565b60008261253857506000611734565b8282028284828161254557fe5b04146124a35760405162461bcd60e51b815260040161040890612e29565b60006124a383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061173a565b60006124a383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126f7565b600081815260018301602052604081205480156126a3578354600019808301919081019060009087908390811061261a57fe5b906000526020600020015490508087600001848154811061263757fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061266757fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611734565b6000915050611734565b60006126b9838361272e565b6126ef57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611734565b506000611734565b600081836127185760405162461bcd60e51b81526004016104089190612d56565b50600083858161272457fe5b0495945050505050565b60009081526001919091016020526040902054151590565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b80356001600160a01b03811681146105ee57600080fd5b60008083601f8401126127b2578182fd5b5081356001600160401b038111156127c8578182fd5b60208301915083602080830285010111156127e257600080fd5b9250929050565b6000602082840312156127fa578081fd5b6124a38261278a565b600080600060608486031215612817578182fd5b6128208461278a565b925061282e6020850161278a565b915061283c6040850161278a565b90509250925092565b60008060408385031215612857578182fd5b6128608361278a565b946020939093013593505050565b60008060208385031215612880578182fd5b82356001600160401b03811115612895578283fd5b6128a1858286016127a1565b90969095509350505050565b600080600080608085870312156128c2578081fd5b843580151581146128d1578182fd5b966020860135965060408601359560600135945092505050565b6000602082840312156128fc578081fd5b81516001600160401b0380821115612912578283fd5b818401915084601f830112612925578283fd5b81518181111561293157fe5b604051601f8201601f19168101602001838111828210171561294f57fe5b604052818152838201602001871015612966578485fd5b6118b48260208301602087016130e5565b600060208284031215612988578081fd5b5035919050565b6000602082840312156129a0578081fd5b5051919050565b60008060008060008060c087890312156129bf578182fd5b86359550602087013594506040870135935060608701359250608087013591506129eb60a0880161278a565b90509295509295509295565b60008060408385031215612a09578182fd5b50508035926020909101359150565b600080600080600060808688031215612a2f578081fd5b8535945060208601359350612a466040870161278a565b925060608601356001600160401b0380821115612a61578283fd5b818801915088601f830112612a74578283fd5b813581811115612a82578384fd5b896020828501011115612a93578384fd5b9699959850939650602001949392505050565b600080600080600060a08688031215612abd578283fd5b85359450602086013593506040860135612ad681613111565b94979396509394606081013594506080013592915050565b600060208284031215612aff578081fd5b81516124a381613111565b15159052565b65ffffffffffff169052565b6001600160401b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039889168152969097166020870152604086019490945260608501929092521515608084015260ff1660a083015260c082015260e08101919091526101000190565b6001600160a01b039890981688526001600160a01b03199690961660208801526001600160401b03948516604088015292841660608701529216608085015265ffffffffffff90911660a0840152151560c083015260e08201526101000190565b602080825282518282018190526000919060409081850190868401855b82811015612d0157815180516001600160a01b03168552868101516001600160a01b03191687860152858101516001600160401b031686860152606080820151612ca682880182612b1c565b5050608080820151612cba82880182612b1c565b505060a080820151612cce82880182612b10565b505060c080820151612ce282880182612b0a565b505060e090810151908501526101009093019290850190600101612c5a565b5091979650505050505050565b901515815260200190565b90815260200190565b9182521515602082015260400190565b938452602084019290925260408301526001600160a01b0316606082015260800190565b6000602082528251806020840152612d758160408501602087016130e5565b601f01601f19169190910160400192915050565b6020808252600c908201526b085a5b9a5d1a585b1a5e995960a21b604082015260600190565b602080825260089082015267085c195c98d95b9d60c21b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b602080825260079082015266085c185d5cd95960ca1b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600d908201526c216d61785f6c6576657261676560981b604082015260600190565b60208082526008908201526721746f6f5f6c6f7760c01b604082015260600190565b60208082526007908201526610b6b0b933b4b760c91b604082015260600190565b6020808252600b908201526a10b830bab9b2b22ab9b2b960a91b604082015260600190565b602080825260099082015268216c6576657261676560b81b604082015260600190565b60208082526010908201526f085d5cd95c97db9bdd17dc185d5cd95960821b604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b60208082526009908201526821746f6f5f6d616e7960b81b604082015260600190565b60208082526017908201527f536166654d6174683a2063617374206f766572666c6f77000000000000000000604082015260600190565b6020808252818101527f55696e74456e756d657261626c655365743a204f55545f4f465f424f554e4453604082015260600190565b60208082526006908201526508599bdd5b9960d21b604082015260600190565b602080825260079082015266085cde5b589bdb60ca1b604082015260600190565b958652931515602086015260408501929092526060840152608083015260a082015260c00190565b918252602082015260400190565b60008582528460208301526060604083015282606083015282846080840137818301608090810191909152601f909201601f191601019392505050565b958652602086019490945260408501929092526001600160401b03908116606085015260808401919091521660a082015260c00190565b60005b838110156131005781810151838201526020016130e8565b838111156108955750506000910152565b60ff8116811461312057600080fd5b5056fea2646970667358221220a90a35f9a76195efe9dffbde0f321e645ef3f8aef0745e67fbbe75a7a19ea28b64736f6c63430007030033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.