Contract 0x9b404BAB12CE0D5039e7313d9e24f4b5c8E8E8e3

Txn Hash Method
Block
From
To
Value [Txn Fee]
0xe829a2089e783741d223b2e30e5726aad7d237f3d8d5b685028ae2abea54cf5aDeposit Margin53082422021-06-04 14:53:42140 days 12 hrs ago0x2baa211d7e62593ba379df362f23e7b813d760ad IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000144221
0x845672bcad7a15ed03ba8d9f6a442cca69feeb18e15813dd1f992a4084a0470aRemove Liquidity53075492021-06-04 14:19:03140 days 13 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0000740871
0xb254c8b3a56df8c0ccc03d18c457a781977e5b1e594fa2199c7ad1d2e4194c17Approve Migratio...53072832021-06-04 14:05:45140 days 13 hrs ago0x05d8bf0182858079815d385cce77df7b2836c1da IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0000759561
0x6c355f3c88109e3846b83ac6f5fbb06e4246444e32ade08d9060e244b27ee2e1Remove Liquidity53070132021-06-04 13:52:15140 days 13 hrs ago0x2752624f4878c36d1933aeb1cce9395490e9fc55 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001572221
0xcf9da131e48908f4df989397883335ecbf9783bf717825d7165a9bfeab253b46Remove Liquidity53069472021-06-04 13:48:57140 days 14 hrs ago0x2752624f4878c36d1933aeb1cce9395490e9fc55 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0000740751
0xa36830aeafd0e90d9464e28d4370e2476550409714ccec633ef0ad87a5221b00Remove Liquidity53069342021-06-04 13:48:18140 days 14 hrs ago0x2752624f4878c36d1933aeb1cce9395490e9fc55 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000740810
0x3259d771e71ef9b0db2c3b5cf153edcec129665dedd00771276298c966a6dacbRemove Liquidity53061752021-06-04 13:10:21140 days 14 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001481842
0x082de650c1ec186907a6391eb29a8e6ef0660cfb299d579b079e2e600978dd80Remove Liquidity53060992021-06-04 13:06:33140 days 14 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000148152
0xc7a901158ad6bc449a6ebb475a3e88ff0dbb64777498ec0d9338f011a3894787Remove Liquidity53060762021-06-04 13:05:24140 days 14 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.00162938622
0x3374e63a5cc4a3ca2bc511c293e29954b77796508124ec172e143e1540fdd132Remove Liquidity53060642021-06-04 13:04:48140 days 14 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.00163002422
0x86e60bfc662c5ba0b27c0339ac50e517173f1d6dc8f53db6fdd309f4bb632819Remove Liquidity53046502021-06-04 11:54:05140 days 15 hrs ago0x39e224ce4b6c4c33f91b5c2bbfc50e7f7e9d6d8b IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.00016557241.2
0x3a5b25567f1f65799c79d98f3cc200decaa71dbfcbfa60f4860b7c0e06c9932bWithdraw Margin53023352021-06-04 9:58:19140 days 17 hrs ago0x06f765a2fd2c773b0d2a806cec1874224fcef000 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001323081
0x018721e592af930abbae415e5833a4d6a1e0036125c0c057863182cf6ba416c1Trade With Margi...53023042021-06-04 9:56:46140 days 17 hrs ago0x06f765a2fd2c773b0d2a806cec1874224fcef000 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0002352422
0x22df30e75496dc83e00ca14109277b03ab92a7e222640a15024f70cfb231c612Remove Liquidity53022422021-06-04 9:53:40140 days 17 hrs ago0x06f765a2fd2c773b0d2a806cec1874224fcef000 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001379631
0x4a758e00894eef6f39d24371c57f7976375955a8661ae8fb3f575b5dd2517323Remove Liquidity53017422021-06-04 9:28:40140 days 18 hrs ago0x7d1481f63f063f1ef7b2c09f888fc081b568ff90 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000122981
0x99c81333e8013c2a9186b268707e601e1d4621f4efd7d35715e263506ed146b4Remove Liquidity53011812021-06-04 9:00:37140 days 18 hrs ago0x1826a1e85875fb744efd8aec0d58850f0982dd1f IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.00017059561.2
0x99725f900231d78d7f8ffd6196aa2e9cea93bd9420cd7a613d11feaadcf6da72Remove Liquidity52719812021-06-03 8:40:35141 days 19 hrs ago0x7d1481f63f063f1ef7b2c09f888fc081b568ff90 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0003359410
0x45a4180443a6de86e9040f73cb14a109c6b1ddbe7392eb265bd59caae4a0008aRemove Liquidity52719652021-06-03 8:39:47141 days 19 hrs ago0x7d1481f63f063f1ef7b2c09f888fc081b568ff90 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0000335821
0xf481e72e2b604be90c298fe1dea53bb19e4bbd3dacb587293729575e23e66f4bPrepare Migratio...52207392021-06-01 13:58:27143 days 13 hrs ago0x05d8bf0182858079815d385cce77df7b2836c1da IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0000661231
0x0d32ae6df14f3f29aacb07f424b8ecc39fbbf9f3e73bc522c613601c8de0c786Add Liquidity51959722021-05-31 17:20:06144 days 10 hrs ago0x7d1481f63f063f1ef7b2c09f888fc081b568ff90 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001481111
0xeae97bd1369d649befda198c36e7f53c4bf0f969c6d3a6fa25430dd2d6c3bc97Remove Liquidity51948132021-05-31 16:22:09144 days 11 hrs ago0x06f765a2fd2c773b0d2a806cec1874224fcef000 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000157221
0x2ae6cf416e3fc5fe618caa6d2f4a8f98953d398dc0a5626699b17addcc90801eAdd Liquidity51943992021-05-31 16:01:27144 days 11 hrs ago0x2752624f4878c36d1933aeb1cce9395490e9fc55 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.0001330991
0x1f7753b89512e1d6d3b42138272e31c7be4fb16bd320cb1f0b0cef0cb02e94e4Remove Liquidity51941482021-05-31 15:48:54144 days 12 hrs ago0x2752624f4878c36d1933aeb1cce9395490e9fc55 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000157221
0x9752591ecbf474177430cbe034d6430fe2365f504f72e0a9487586809cb3d336Add Liquidity51915032021-05-31 13:36:39144 days 14 hrs ago0x027fca5dce8baa10e93ca93d0f2150e7ca4d4107 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.00439091433
0xa2a6f361770cd1d71ed71bdaad81b44fe5ea1bdc6b389109a9ca147721bfe987Remove Liquidity51911852021-05-31 13:20:45144 days 14 hrs ago0x7d1481f63f063f1ef7b2c09f888fc081b568ff90 IN  0x9b404bab12ce0d5039e7313d9e24f4b5c8e8e8e30 HT0.000142181
[ Download CSV Export 
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0xb1602a90656bc7c4f9508385a5a6a85615521735bc9ee245b5a35e2efa35d8a525579142021-03-01 2:55:02236 days 54 mins ago 0xefc45ef44b2fbb08a6a6452e24bcfa0093ad77c5  Contract Creation0 HT
[ Download CSV Export 
Loading

Minimal Proxy Contract for 0x8846f3f52817dd369941097a0f20d304bebaa761

Contract Name:
PerpetualPool

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license
Decompile ByteCode

Contract Source Code (Solidity Multiple files format)

File 1 of 19: PerpetualPool.sol
// SPDX-License-Identifier: MIT

// Version: 0.1.0, 1/20/2021

pragma solidity >=0.6.2 <0.8.0;

import "./IERC20.sol";
import "./IPToken.sol";
import "./ILToken.sol";
import "./IOracle.sol";
import "./ILiquidatorQualifier.sol";
import "./IMigratablePool.sol";
import "./IPreMiningPool.sol";
import "./IPerpetualPool.sol";
import "./SafeERC20.sol";
import "./MixedSafeMathWithUnit.sol";
import "./MigratablePool.sol";

/**
 * @title Deri Protocol PerpetualPool Implementation
 */
contract PerpetualPool is IMigratablePool, IPerpetualPool, MigratablePool {

    using MixedSafeMathWithUnit for uint256;
    using MixedSafeMathWithUnit for int256;
    using SafeERC20 for IERC20;

    // Trading symbol
    string private _symbol;

    // Last price
    uint256 private _price;
    // Last price timestamp
    uint256 private _lastPriceTimestamp;
    // Last price block number
    uint256 private _lastPriceBlockNumber;

    // Base token contract, all settlements are done in base token
    IERC20  private _bToken;
    // Base token decimals
    uint256 private _bDecimals;
    // Position token contract
    IPToken private _pToken;
    // Liquidity provider token contract
    ILToken private _lToken;
    // For on-chain oracle, it is a contract and must have getPrice() method to fetch current price
    // For off-chain signed price oracle, it is an EOA
    // and its address is used to verify price signature
    IOracle private _oracle;
    // Is on-chain oracle, or off-chain oracle with signed price
    bool private _isContractOracle;
    // LiquidatorQualifier contract to check if an address can call liquidate function
    // If this address is 0, means no liquidator qualification check, anyone can call liquidate
    ILiquidatorQualifier private _liquidatorQualifier;

    // Contract multiplier
    uint256 private _multiplier;
    // Trading fee ratio
    uint256 private _feeRatio;
    // Minimum pool margin ratio
    uint256 private _minPoolMarginRatio;
    // Minimum initial margin ratio for trader
    uint256 private _minInitialMarginRatio;
    // Minimum maintenance margin ratio for trader
    uint256 private _minMaintenanceMarginRatio;
    // Minimum amount requirement when add liquidity
    uint256 private _minAddLiquidity;
    // Redemption fee ratio when removing liquidity
    uint256 private _redemptionFeeRatio;
    // Funding rate coefficient
    uint256 private _fundingRateCoefficient;
    // Minimum liquidation reward
    uint256 private _minLiquidationReward;
    // Maximum liquidation reward
    uint256 private _maxLiquidationReward;
    // Cutting ratio for liquidator
    uint256 private _liquidationCutRatio;
    // Price delay allowance in seconds
    uint256 private _priceDelayAllowance;

    // Recorded cumulative funding rate, overflow of this value is intended
    int256  private _cumuFundingRate;
    // Last block number when cumulative funding rate was recorded
    uint256 private _cumuFundingRateBlock;
    // Total liquidity pool holds
    uint256 private _liquidity;
    // Total net volume of all traders in the pool
    int256  private _tradersNetVolume;
    // Total cost of current traders net volume
    // The cost for a long position is positive, and short position is negative
    int256  private _tradersNetCost;

    bool private _mutex;
    // Locker to prevent reentry
    modifier _lock_() {
        require(!_mutex, "PerpetualPool: reentry");
        _mutex = true;
        _;
        _mutex = false;
    }

    /**
     * @dev A dummy constructor, which deos not initialize any storage variables
     * A template will be deployed with no initialization and real pool will be cloned
     * from this template (same as create_forwarder_to mechanism in Vyper),
     * and use `initialize` to initialize all storage variables
     */
    constructor () {}

    /**
     * @dev See {IPerpetualPool}.{initialize}
     */
    function initialize(
        string memory symbol_,
        address[5] calldata addresses_,
        uint256[12] calldata parameters_
    ) public override {
        require(bytes(_symbol).length == 0 && _controller == address(0), "PerpetualPool: already initialized");

        _controller = msg.sender;
        _symbol = symbol_;

        _bToken = IERC20(addresses_[0]);
        _bDecimals = _bToken.decimals();
        _pToken = IPToken(addresses_[1]);
        _lToken = ILToken(addresses_[2]);
        _oracle = IOracle(addresses_[3]);
        _isContractOracle = _isContract(address(_oracle));
        _liquidatorQualifier = ILiquidatorQualifier(addresses_[4]);

        _multiplier = parameters_[0];
        _feeRatio = parameters_[1];
        _minPoolMarginRatio = parameters_[2];
        _minInitialMarginRatio = parameters_[3];
        _minMaintenanceMarginRatio = parameters_[4];
        _minAddLiquidity = parameters_[5];
        _redemptionFeeRatio = parameters_[6];
        _fundingRateCoefficient = parameters_[7];
        _minLiquidationReward = parameters_[8];
        _maxLiquidationReward = parameters_[9];
        _liquidationCutRatio = parameters_[10];
        _priceDelayAllowance = parameters_[11];
    }

    /**
     * @dev See {IMigratablePool}.{approveMigration}
     */
    function approveMigration() public override _controller_ {
        require(_migrationTimestamp != 0 && block.timestamp >= _migrationTimestamp, "PerpetualPool: migrationTimestamp not met yet");
        // approve new pool to pull all base tokens from this pool
        _bToken.safeApprove(_migrationDestination, uint256(-1));
        // set pToken/lToken to new pool, after redirecting pToken/lToken to new pool, this pool will stop functioning
        _pToken.setPool(_migrationDestination);
        _lToken.setPool(_migrationDestination);
    }

    /**
     * @dev See {IMigratablePool}.{executeMigration}
     */
    function executeMigration(address source) public override _controller_ {
        uint256 migrationTimestamp_ = IPerpetualPool(source).migrationTimestamp();
        address migrationDestination_ = IPerpetualPool(source).migrationDestination();
        require(migrationTimestamp_ != 0 && block.timestamp >= migrationTimestamp_, "PerpetualPool: migrationTimestamp not met yet");
        require(migrationDestination_ == address(this), "PerpetualPool: executeMigration to not destination pool");

        // migrate base token
        _bToken.safeTransferFrom(source, address(this), _bToken.balanceOf(source));

        // // migrate state values from PerpetualPool
        // (int256 cumuFundingRate, uint256 cumuFundingRateBlock, uint256 liquidity, int256 tradersNetVolume, int256 tradersNetCost) = IPerpetualPool(source).getStateValues();
        // _cumuFundingRate = cumuFundingRate;
        // _cumuFundingRateBlock = cumuFundingRateBlock;
        // _liquidity = liquidity;
        // _tradersNetVolume = tradersNetVolume;
        // _tradersNetCost = tradersNetCost;

        // migrate state values from PreMiningPool
        _liquidity = IPreMiningPool(source).getStateValues();

        emit ExecuteMigration(_migrationTimestamp, source, address(this));
    }


    /**
     * @dev See {IPerpetualPool}.{symbol}
     */
    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IPerpetualPool}.{getAddresses}
     */
    function getAddresses() public view override returns (
        address bToken,
        address pToken,
        address lToken,
        address oracle,
        address liquidatorQualifier
    ) {
        return (
            address(_bToken),
            address(_pToken),
            address(_lToken),
            address(_oracle),
            address(_liquidatorQualifier)
        );
    }

    /**
     * @dev See {IPerpetualPool}.{getParameters}
     */
    function getParameters() public view override returns (
        uint256 multiplier,
        uint256 feeRatio,
        uint256 minPoolMarginRatio,
        uint256 minInitialMarginRatio,
        uint256 minMaintenanceMarginRatio,
        uint256 minAddLiquidity,
        uint256 redemptionFeeRatio,
        uint256 fundingRateCoefficient,
        uint256 minLiquidationReward,
        uint256 maxLiquidationReward,
        uint256 liquidationCutRatio,
        uint256 priceDelayAllowance
    ) {
        return (
            _multiplier,
            _feeRatio,
            _minPoolMarginRatio,
            _minInitialMarginRatio,
            _minMaintenanceMarginRatio,
            _minAddLiquidity,
            _redemptionFeeRatio,
            _fundingRateCoefficient,
            _minLiquidationReward,
            _maxLiquidationReward,
            _liquidationCutRatio,
            _priceDelayAllowance
        );
    }

    /**
     * @dev See {IPerpetualPool}.{getStateValues}
     */
    function getStateValues() public view override returns (
        int256 cumuFundingRate,
        uint256 cumuFundingRateBlock,
        uint256 liquidity,
        int256 tradersNetVolume,
        int256 tradersNetCost
    ) {
        return (
            _cumuFundingRate,
            _cumuFundingRateBlock,
            _liquidity,
            _tradersNetVolume,
            _tradersNetCost
        );
    }


    //================================================================================
    // Pool interactions
    //================================================================================

    /**
     * @dev See {IPerpetualPool}.{tradeWithMargin}
     */
    function tradeWithMargin(int256 tradeVolume, uint256 bAmount) public override {
        _updatePriceFromOracle();
        _tradeWithMargin(tradeVolume, bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{tradeWithMargin}
     */
    function tradeWithMargin(
        int256 tradeVolume,
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _tradeWithMargin(tradeVolume, bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{trade}
     */
    function trade(int256 tradeVolume) public override {
        _updatePriceFromOracle();
        _trade(tradeVolume);
    }

    /**
     * @dev See {IPerpetualPool}.{trade}
     */
    function trade(
        int256 tradeVolume,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _trade(tradeVolume);
    }

    /**
     * @dev See {IPerpetualPool}.{depositMargin}
     */
    function depositMargin(uint256 bAmount) public override {
        _updatePriceFromOracle();
        _depositMargin(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{depositMargin}
     */
    function depositMargin(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _depositMargin(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{withdrawMargin}
     */
    function withdrawMargin(uint256 bAmount) public override {
        _updatePriceFromOracle();
        _withdrawMargin(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{withdrawMargin}
     */
    function withdrawMargin(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _withdrawMargin(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{addLiquidity}
     */
    function addLiquidity(uint256 bAmount) public override {
        _updatePriceFromOracle();
        _addLiquidity(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{addLiquidity}
     */
    function addLiquidity(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _addLiquidity(bAmount);
    }

    /**
     * @dev See {IPerpetualPool}.{removeLiquidity}
     */
    function removeLiquidity(uint256 lShares) public override {
        _updatePriceFromOracle();
        _removeLiquidity(lShares);
    }

    /**
     * @dev See {IPerpetualPool}.{removeLiquidity}
     */
    function removeLiquidity(
        uint256 lShares,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        _updatePriceWithSignature(timestamp, price, v, r, s);
        _removeLiquidity(lShares);
    }

    /**
     * @dev See {IPerpetualPool}.{liquidate}
     */
    function liquidate(address owner) public override {
        require(
            address(_liquidatorQualifier) == address(0) || _liquidatorQualifier.isQualifiedLiquidator(msg.sender),
            "PerpetualPool: not quanlified liquidator"
        );
        _updatePriceFromOracle();
        _liquidate(owner, block.timestamp, _price);
    }

    /**
     * @dev See {IPerpetualPool}.{liquidate}
     *
     * A price signature with timestamp after position's lastUpdateTimestamp
     * will be a valid liquidation price
     */
    function liquidate(
        address owner,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        require(
            address(_liquidatorQualifier) == address(0) || _liquidatorQualifier.isQualifiedLiquidator(msg.sender),
            "PerpetualPool: not quanlified liquidator"
        );
        _checkPriceSignature(timestamp, price, v, r, s);
        _liquidate(owner, timestamp, price);
    }


    //================================================================================
    // Pool critic logics
    //================================================================================

    /**
     * @dev Low level tradeWithMargin implementation
     * _lock_ is not need in this function, as sub-functions will apply _lock_
     */
    function _tradeWithMargin(int256 tradeVolume, uint256 bAmount) internal {
        if (bAmount == 0) {
            _trade(tradeVolume);
        } else if (tradeVolume == 0) {
            _depositMargin(bAmount);
        } else {
            _depositMargin(bAmount);
            _trade(tradeVolume);
        }
    }

    /**
     * @dev Low level trade implementation
     */
    function _trade(int256 tradeVolume) internal _lock_ {
        require(tradeVolume != 0, "PerpetualPool: trade with 0 volume");
        require(tradeVolume.reformat(0) == tradeVolume, "PerpetualPool: trade volume must be int");

        // get trader's position, trader must have a position token to call this function
        (int256 volume, int256 cost, int256 lastCumuFundingRate, uint256 margin,) = _pToken.getPosition(msg.sender);

        // update cumulative funding rate
        _updateCumuFundingRate(_price);

        // calculate trader's funding fee
        int256 funding = volume.mul(_cumuFundingRate - lastCumuFundingRate);

        // calculate trading fee for this transaction
        int256 curCost = tradeVolume.mul(_price).mul(_multiplier);
        uint256 fee = _feeRatio.mul(curCost.abs());

        // calculate realized cost
        int256 realizedCost = 0;
        if ((volume >= 0 && tradeVolume >= 0) || (volume <= 0 && tradeVolume <= 0)) {
            // open in same direction, no realized cost
        } else if (volume.abs() <= tradeVolume.abs()) {
            // previous position is flipped
            realizedCost = curCost.mul(volume.abs()).div(tradeVolume.abs()).add(cost);
        } else {
            // previous position is partially closed
            realizedCost = cost.mul(tradeVolume.abs()).div(volume.abs()).add(curCost);
        }

        // total paid in this transaction, could be negative if there is realized pnl
        // this paid amount should be a valid value in base token decimals representation
        int256 paid = funding.add(fee).add(realizedCost).reformat(_bDecimals);

        // settlements
        volume = volume.add(tradeVolume);
        cost = cost.add(curCost).sub(realizedCost);
        margin = margin.sub(paid);
        _tradersNetVolume = _tradersNetVolume.add(tradeVolume);
        _tradersNetCost = _tradersNetCost.add(curCost).sub(realizedCost);
        _liquidity = _liquidity.add(paid);
        lastCumuFundingRate = _cumuFundingRate;

        // check margin requirements
        require(volume == 0 || _calculateMarginRatio(volume, cost, _price, margin) >= _minInitialMarginRatio,
                "PerpetualPool: trader insufficient margin");
        require(_tradersNetVolume == 0 || _calculateMarginRatio(_tradersNetVolume.neg(), _tradersNetCost.neg(), _price, _liquidity) >= _minPoolMarginRatio,
                "PerpetualPool: pool insufficient liquidity");

        _pToken.update(msg.sender, volume, cost, lastCumuFundingRate, margin, block.timestamp);
        emit Trade(msg.sender, tradeVolume, _price);
    }

    /**
     * @dev Low level depositMargin implementation
     */
    function _depositMargin(uint256 bAmount) internal _lock_ {
        require(bAmount != 0, "PerpetualPool: deposit zero margin");
        require(bAmount.reformat(_bDecimals) == bAmount, "PerpetualPool: _depositMargin bAmount not valid");

        bAmount = _deflationCompatibleSafeTransferFrom(msg.sender, address(this), bAmount);
        if (!_pToken.exists(msg.sender)) {
            _pToken.mint(msg.sender, bAmount);
        } else {
            (int256 volume, int256 cost, int256 lastCumuFundingRate, uint256 margin,) = _pToken.getPosition(msg.sender);
            margin = margin.add(bAmount);
            _pToken.update(msg.sender, volume, cost, lastCumuFundingRate, margin, block.timestamp);
        }
        emit DepositMargin(msg.sender, bAmount);
    }

    /**
     * @dev Low level withdrawMargin implementation
     */
    function _withdrawMargin(uint256 bAmount) internal _lock_ {
        require(bAmount != 0, "PerpetualPool: withdraw zero margin");
        require(bAmount.reformat(_bDecimals) == bAmount, "PerpetualPool: _withdrawMargin bAmount not valid");

        (int256 volume, int256 cost, int256 lastCumuFundingRate, uint256 margin,) = _pToken.getPosition(msg.sender);
        _updateCumuFundingRate(_price);

        int256 funding = volume.mul(_cumuFundingRate - lastCumuFundingRate).reformat(_bDecimals);
        margin = margin.sub(funding).sub(bAmount);
        _liquidity = _liquidity.add(funding);
        lastCumuFundingRate = _cumuFundingRate;

        require(volume == 0 || _calculateMarginRatio(volume, cost, _price, margin) >= _minInitialMarginRatio,
                "PerpetualPool: withdraw cause insufficient margin");

        _pToken.update(msg.sender, volume, cost, lastCumuFundingRate, margin, block.timestamp);
        _bToken.safeTransfer(msg.sender, bAmount.rescale(_bDecimals));
        emit WithdrawMargin(msg.sender, bAmount);
    }

    /**
     * @dev Low level addLiquidity implementation
     */
    function _addLiquidity(uint256 bAmount) internal _lock_ {
        require(bAmount >= _minAddLiquidity, "PerpetualPool: add liquidity less than minimum requirement");
        require(bAmount.reformat(_bDecimals) == bAmount, "PerpetualPool: _addLiquidity bAmount not valid");

        _updateCumuFundingRate(_price);

        bAmount = _deflationCompatibleSafeTransferFrom(msg.sender, address(this), bAmount);

        uint256 poolDynamicEquity = _liquidity.add(_tradersNetCost.sub(_tradersNetVolume.mul(_price).mul(_multiplier)));
        uint256 totalSupply = _lToken.totalSupply();
        uint256 lShares;
        if (totalSupply == 0) {
            lShares = bAmount;
        } else {
            lShares = bAmount.mul(totalSupply).div(poolDynamicEquity);
        }

        _lToken.mint(msg.sender, lShares);
        _liquidity = _liquidity.add(bAmount);

        emit AddLiquidity(msg.sender, lShares, bAmount);
    }

    /**
     * @dev Low level removeLiquidity implementation
     */
    function _removeLiquidity(uint256 lShares) internal _lock_ {
        require(lShares > 0, "PerpetualPool: remove 0 liquidity");
        uint256 balance = _lToken.balanceOf(msg.sender);
        require(lShares == balance || balance.sub(lShares) >= 10**18, "PerpetualPool: remaining liquidity shares must be 0 or at least 1");

        _updateCumuFundingRate(_price);

        uint256 poolDynamicEquity = _liquidity.add(_tradersNetCost.sub(_tradersNetVolume.mul(_price).mul(_multiplier)));
        uint256 totalSupply = _lToken.totalSupply();
        uint256 bAmount = lShares.mul(poolDynamicEquity).div(totalSupply);
        if (lShares < totalSupply) {
            bAmount = bAmount.sub(bAmount.mul(_redemptionFeeRatio));
        }
        bAmount = bAmount.reformat(_bDecimals);

        _liquidity = _liquidity.sub(bAmount);
        require(_tradersNetVolume == 0 || _calculateMarginRatio(_tradersNetVolume.neg(), _tradersNetCost.neg(), _price, _liquidity) >= _minPoolMarginRatio,
                "PerpetualPool: remove liquidity cause pool insufficient liquidity");

        _lToken.burn(msg.sender, lShares);
        _bToken.safeTransfer(msg.sender, bAmount.rescale(_bDecimals));

        emit RemoveLiquidity(msg.sender, lShares, bAmount);
    }

    /**
     * @dev Low level liquidate implementation
     */
    function _liquidate(address owner, uint256 timestamp, uint256 price) internal _lock_ {
        (int256 volume, int256 cost, , uint256 margin, uint256 lastUpdateTimestamp) = _pToken.getPosition(owner);
        require(timestamp > lastUpdateTimestamp, "PerpetualPool: liquidate price is before position timestamp");

        int256 pnl = volume.mul(price).mul(_multiplier).sub(cost);
        require(pnl.add(margin) <= 0 || _calculateMarginRatio(volume, cost, price, margin) < _minMaintenanceMarginRatio, "PerpetualPool: cannot liquidate");

        _liquidity = _liquidity.add(margin);
        _tradersNetVolume = _tradersNetVolume.sub(volume);
        _tradersNetCost = _tradersNetCost.sub(cost);
        _pToken.update(owner, 0, 0, 0, 0, 0);

        uint256 reward;
        if (margin <= _minLiquidationReward) {
            reward = _minLiquidationReward;
        } else if (margin >= _maxLiquidationReward) {
            reward = _maxLiquidationReward;
        } else {
            reward = margin.sub(_minLiquidationReward).mul(_liquidationCutRatio).add(_minLiquidationReward);
        }
        reward = reward.reformat(_bDecimals);

        _liquidity = _liquidity.sub(reward);
        _bToken.safeTransfer(msg.sender, reward.rescale(_bDecimals));

        emit Liquidate(owner, volume, cost, margin, timestamp, price, msg.sender, reward);
    }


    //================================================================================
    // Helpers
    //================================================================================

    /**
     * @dev Check if an address is a contract
     */
    function _isContract(address addr) internal view returns (bool) {
        uint32 size;
        assembly {
            size := extcodesize(addr)
        }
        return size > 0;
    }

    /**
     *                            margin + unrealizedPnl
     *@dev margin ratio = --------------------------------------
     *                       abs(volume) * price * multiplier
     *
     * volume cannot be zero
     */
    function _calculateMarginRatio(int256 volume, int256 cost, uint256 price, uint256 margin)
        internal view returns (uint256)
    {
        int256 value = volume.mul(price).mul(_multiplier);
        uint256 ratio = margin.add(value.sub(cost)).div(value.abs());
        return ratio;
    }

    /**
     *                          _tradersNetVolume * price * multiplier
     * @dev rate per block = ------------------------------------------- * coefficient
     *                                      _liquidity
     */
    function _updateCumuFundingRate(uint256 price) private {
        if (block.number > _cumuFundingRateBlock) {
            int256 rate;
            if (_liquidity != 0) {
                rate = _tradersNetVolume.mul(price).mul(_multiplier).mul(_fundingRateCoefficient).div(_liquidity);
            } else {
                rate = 0;
            }
            int256 delta = rate * (int256(block.number.sub(_cumuFundingRateBlock))); // overflow is intended
            _cumuFundingRate += delta; // overflow is intended
            _cumuFundingRateBlock = block.number;
        }
    }

    /**
     * @dev Check price signature
     */
    function _checkPriceSignature(uint256 timestamp, uint256 price, uint8 v, bytes32 r, bytes32 s)
        internal view
    {
        require(v == 27 || v == 28, "PerpetualPool: v not valid");
        bytes32 message = keccak256(abi.encodePacked(_symbol, timestamp, price));
        bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
        address signer = ecrecover(hash, v, r, s);
        require(signer == address(_oracle), "PerpetualPool: price not signed by oracle");
    }

    /**
     * @dev Check price signature to verify if price is authorized, and update _price
     * only check/update once for one block
     */
    function _updatePriceWithSignature(
        uint256 timestamp, uint256 price, uint8 v, bytes32 r, bytes32 s
    ) internal
    {
        if (block.number != _lastPriceBlockNumber) {
            require(timestamp >= _lastPriceTimestamp, "PerpetualPool: price is not the newest");
            require(block.timestamp - timestamp <= _priceDelayAllowance, "PerpetualPool: price is older than allowance");

            _checkPriceSignature(timestamp, price, v, r, s);

            _price = price;
            _lastPriceTimestamp = timestamp;
            _lastPriceBlockNumber = block.number;
        }
    }

    /**
     * @dev Update price from on-chain Oracle
     */
    function _updatePriceFromOracle() internal {
        require(_isContractOracle, "PerpetualPool: wrong type of orcale");
        if (block.number != _lastPriceBlockNumber) {
            _price = _oracle.getPrice();
            _lastPriceBlockNumber = block.number;
        }
    }

    /**
     * @dev safeTransferFrom for base token with deflation protection
     * Returns the actual received amount in base token (as base 10**18)
     */
    function _deflationCompatibleSafeTransferFrom(address from, address to, uint256 amount) internal returns (uint256) {
        uint256 preBalance = _bToken.balanceOf(to);
        _bToken.safeTransferFrom(from, to, amount.rescale(_bDecimals));
        uint256 curBalance = _bToken.balanceOf(to);

        uint256 a = curBalance.sub(preBalance);
        uint256 b = 10**18;
        uint256 c = a * b;
        require(c / b == a, "PreMiningPool: _deflationCompatibleSafeTransferFrom multiplication overflows");

        uint256 actualReceivedAmount = c / (10 ** _bDecimals);
        return actualReceivedAmount;
    }

}

File 2 of 19: Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 3 of 19: ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}

File 4 of 19: ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./Address.sol";
import "./ERC165.sol";

/**
 * @dev ERC721 Non-Fungible Token Implementation
 *
 * Exert uniqueness of owner: one owner can only have one token
 */
contract ERC721 is IERC721, ERC165 {

    using Address for address;

    /*
     * Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     * which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
     */
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x081812fc ^ 0xe985e9c5 ^
     *        0x095ea7b3 ^ 0xa22cb465 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    // Mapping from owner address to tokenId
    // tokenId starts from 1, 0 is reserved for nonexistent token
    // One owner can only own one token in this contract
    mapping (address => uint256) _ownerTokenId;

    // Mapping from tokenId to owner
    mapping (uint256 => address) _tokenIdOwner;

    // Mapping from tokenId to approved operator
    mapping (uint256 => address) _tokenIdOperator;

    // Mapping from owner to operator for all approval
    mapping (address => mapping (address => bool)) _ownerOperator;


    constructor () {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev See {IERC721}.{balanceOf}
     */
    function balanceOf(address owner) public view override returns (uint256) {
        if (_exists(owner)) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * @dev See {IERC721}.{ownerOf}
     */
    function ownerOf(uint256 tokenId) public view override returns (address) {
        require(_exists(tokenId), "ERC721: ownerOf for nonexistent tokenId");
        return _tokenIdOwner[tokenId];
    }

    /**
     * @dev See {IERC721}.{getApproved}
     */
    function getApproved(uint256 tokenId) public view override returns (address) {
        require(_exists(tokenId), "ERC721: getApproved for nonexistent tokenId");
        return _tokenIdOperator[tokenId];
    }

    /**
     * @dev See {IERC721}.{isApprovedForAll}
     */
    function isApprovedForAll(address owner, address operator) public view override returns (bool) {
        require(_exists(owner), "ERC721: isApprovedForAll for nonexistent owner");
        return _ownerOperator[owner][operator];
    }

    /**
     * @dev See {IERC721}.{approve}
     */
    function approve(address operator, uint256 tokenId) public override {
        require(msg.sender == ownerOf(tokenId), "ERC721: approve caller is not owner");
        _approve(msg.sender, operator, tokenId);
    }

    /**
     * @dev See {IERC721}.{setApprovalForAll}
     */
    function setApprovalForAll(address operator, bool approved) public override {
        require(_exists(msg.sender), "ERC721: setApprovalForAll caller is not existent owner");
        _ownerOperator[msg.sender][operator] = approved;
        emit ApprovalForAll(msg.sender, operator, approved);
    }

    /**
     * @dev See {IERC721}.{transferFrom}
     */
    function transferFrom(address from, address to, uint256 tokenId) public override {
        _validateTransfer(msg.sender, from, to, tokenId);
        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721}.{safeTransferFrom}
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721}.{safeTransferFrom}
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
        public override
    {
        _validateTransfer(msg.sender, from, to, tokenId);
        _safeTransfer(from, to, tokenId, data);
    }


    /**
     * @dev Returns if owner exists.
     */
    function _exists(address owner) internal view returns (bool) {
        return _ownerTokenId[owner] != 0;
    }

    /**
     * @dev Returns if tokenId exists.
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        return _tokenIdOwner[tokenId] != address(0);
    }

    /**
     * @dev Approve `operator` to manage `tokenId`, owned by `owner`
     *
     * Validation check on parameters should be carried out before calling this function.
     */
    function _approve(address owner, address operator, uint256 tokenId) internal {
        _tokenIdOperator[tokenId] = operator;
        emit Approval(owner, operator, tokenId);
    }

    /**
     * @dev Validate transferFrom parameters
     */
    function _validateTransfer(address operator, address from, address to, uint256 tokenId)
        internal view
    {
        require(from == ownerOf(tokenId), "ERC721: transfer not owned token");
        require(to != address(0), "ERC721: transfer to 0 address");
        require(!_exists(to), "ERC721: transfer to already existent owner");
        require(
            operator == from || _tokenIdOperator[tokenId] == operator || _ownerOperator[from][operator],
            "ERC721: transfer caller is not owner nor approved"
        );
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * Validation check on parameters should be carried out before calling this function.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal {
        // clear previous ownership and approvals
        delete _ownerTokenId[from];
        delete _tokenIdOperator[tokenId];

        // set up new owner
        _ownerTokenId[to] = tokenId;
        _tokenIdOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract
     * recipients are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Validation check on parameters should be carried out before calling this function.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     *      The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID.
     * @param to target address that will receive the tokens.
     * @param tokenId uint256 ID of the token to be transferred.
     * @param data bytes optional data to send along with the call.
     * @return bool whether the call correctly returned the expected magic value.
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }
        bytes memory returndata = to.functionCall(abi.encodeWithSelector(
            IERC721Receiver(to).onERC721Received.selector,
            msg.sender,
            from,
            tokenId,
            data
        ), "ERC721: transfer to non ERC721Receiver implementer");
        bytes4 retval = abi.decode(returndata, (bytes4));
        return (retval == _ERC721_RECEIVED);
    }

}

File 5 of 19: IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 6 of 19: IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {

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

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

    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() external view returns (uint8);

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

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

}

File 7 of 19: IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `operator` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed operator, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address);

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Gives permission to `operator` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address
     * clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address operator, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token
     *   by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first
     * that contract recipients are aware of the ERC721 protocol to prevent
     * tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token
     *   by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement
     *   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token
     *   by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement
     *   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

File 8 of 19: IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via
     * {IERC721-safeTransferFrom} by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient,
     * the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
        external returns (bytes4);
}

File 9 of 19: ILiquidatorQualifier.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @title Deri Protocol liquidator qualifier interface
 */
interface ILiquidatorQualifier {

    /**
     * @dev Check if `liquidator` is a qualified liquidator to call the `liquidate` function in PerpetualPool
     */
    function isQualifiedLiquidator(address liquidator) external view returns (bool);

}

File 10 of 19: ILToken.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC20.sol";

/**
 * @title Deri Protocol liquidity provider token interface
 */
interface ILToken is IERC20 {

    /**
     * @dev Set the pool address of this LToken
     * pool is the only controller of this contract
     * can only be called by current pool
     */
    function setPool(address newPool) external;

    /**
     * @dev Returns address of pool
     */
    function pool() external view returns (address);

    /**
     * @dev Mint LToken to `account` of `amount`
     *
     * Can only be called by pool
     * `account` cannot be zero address
     */
    function mint(address account, uint256 amount) external;

    /**
     * @dev Burn `amount` LToken of `account`
     *
     * Can only be called by pool
     * `account` cannot be zero address
     * `account` must owns at least `amount` LToken
     */
    function burn(address account, uint256 amount) external;

}

File 11 of 19: IMigratablePool.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Deri Protocol migratable pool interface
 */
interface IMigratablePool {

    /**
     * @dev Emitted when migration is prepared
     * `source` pool will be migrated to `target` pool after `migrationTimestamp`
     */
    event PrepareMigration(uint256 migrationTimestamp, address source, address target);

    /**
     * @dev Emmited when migration is executed
     * `source` pool is migrated to `target` pool
     */
    event ExecuteMigration(uint256 migrationTimestamp, address source, address target);

    /**
     * @dev Set controller to `newController`
     *
     * can only be called by current controller or the controller has not been set
     */
    function setController(address newController) external;

    /**
     * @dev Returns address of current controller
     */
    function controller() external view returns (address);

    /**
     * @dev Returns the migrationTimestamp of this pool, zero means not set
     */
    function migrationTimestamp() external view returns (uint256);

    /**
     * @dev Returns the destination pool this pool will migrate to after grace period
     * zero address means not set
     */
    function migrationDestination() external view returns (address);

    /**
     * @dev Prepare a migration from this pool to `newPool` with `graceDays` as grace period
     * `graceDays` must be at least 3 days from now, allow users to verify the `newPool` code
     *
     * can only be called by controller
     */
    function prepareMigration(address newPool, uint256 graceDays) external;

    /**
     * @dev Approve migration to `newPool` when grace period ends
     * after approvement, current pool will stop functioning
     *
     * can only be called by controller
     */
    function approveMigration() external;

    /**
     * @dev Called from the `newPool` to migrate from `source` pool
     * the grace period of `source` pool must ends
     * current pool must be the destination pool set before grace period in the `source` pool
     *
     * can only be called by controller
     */
    function executeMigration(address source) external;

}

File 12 of 19: IOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @title Oracle interface
 */
interface IOracle {

    function getPrice() external view returns (uint256);

}

File 13 of 19: IPerpetualPool.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IMigratablePool.sol";

/**
 * @title Deri Protocol PerpetualPool Interface
 */
interface IPerpetualPool is IMigratablePool {

    /**
     * @dev Emitted when `owner` traded `tradeVolume` at `price` in pool
     */
    event Trade(address indexed owner, int256 tradeVolume, uint256 price);

    /**
     * @dev Emitted when `owner` deposit margin of `bAmount` in base token
     */
    event DepositMargin(address indexed owner, uint256 bAmount);

    /**
     * @dev Emitted when `owner` withdraw margin of `bAmount` in base token
     */
    event WithdrawMargin(address indexed owner, uint256 bAmount);

    /**
     * @dev Emitted when `owner` add liquidity of `bAmount`,
     * and receive `lShares` liquidity token
     */
    event AddLiquidity(address indexed owner, uint256 lShares, uint256 bAmount);

    /**
     * @dev Emitted when `owner` burn `lShares` of liquidity token,
     * and receive `bAmount` in base token
     */
    event RemoveLiquidity(address indexed owner, uint256 lShares, uint256 bAmount);

    /**
     * @dev Emitted when `owner`'s position is liquidated
     */
    event Liquidate(
        address indexed owner,
        int256 volume,
        int256 cost,
        uint256 margin,
        uint256 timestamp,
        uint256 price,
        address liquidator,
        uint256 reward
    );

    /**
     * @dev Initialize pool
     *
     * addresses:
     *      bToken
     *      pToken
     *      lToken
     *      oracle
     *      liquidatorQualifier
     *
     * parameters:
     *      multiplier
     *      feeRatio
     *      minPoolMarginRatio
     *      minInitialMarginRatio
     *      minMaintenanceMarginRatio
     *      minAddLiquidity
     *      redemptionFeeRatio
     *      fundingRateCoefficient
     *      minLiquidationReward
     *      maxLiquidationReward
     *      liquidationCutRatio
     *      priceDelayAllowance
     */
    function initialize(
        string memory symbol_,
        address[5] calldata addresses_,
        uint256[12] calldata parameters_
    ) external;

    /**
     * @dev Returns trading symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns addresses of (bToken, pToken, lToken, oracle) in this pool
     */
    function getAddresses() external view returns (
        address bToken,
        address pToken,
        address lToken,
        address oracle,
        address liquidatorQualifier
    );

    /**
     * @dev Returns parameters of this pool
     */
    function getParameters() external view returns (
        uint256 multiplier,
        uint256 feeRatio,
        uint256 minPoolMarginRatio,
        uint256 minInitialMarginRatio,
        uint256 minMaintenanceMarginRatio,
        uint256 minAddLiquidity,
        uint256 redemptionFeeRatio,
        uint256 fundingRateCoefficient,
        uint256 minLiquidationReward,
        uint256 maxLiquidationReward,
        uint256 liquidationCutRatio,
        uint256 priceDelayAllowance
    );

    /**
     * @dev Returns currents state values of this pool
     */
    function getStateValues() external view returns (
        int256 cumuFundingRate,
        uint256 cumuFundingRateBlock,
        uint256 liquidity,
        int256 tradersNetVolume,
        int256 tradersNetCost
    );

    /**
     * @dev Trade `tradeVolume` with pool while deposit margin of `bAmount` in base token
     * This function is the combination of `depositMargin` and `trade`
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function tradeWithMargin(int256 tradeVolume, uint256 bAmount) external;
    function tradeWithMargin(
        int256 tradeVolume,
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Trade `tradeVolume` with pool
     *
     * A trader must hold a Position Token (with sufficient margin in PToken)
     * before calling this function
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function trade(int256 tradeVolume) external;
    function trade(
        int256 tradeVolume,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Deposit margin of `bAmount` in base token
     *
     * If trader does not hold position token, a new position token will be minted
     * to trader with supplied margin
     * Otherwise, the position token of trader will be updated with added margin
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function depositMargin(uint256 bAmount) external;
    function depositMargin(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Withdraw margin of `bAmount` in base token
     *
     * Trader must hold a position token
     * If trader holds any open position in position token, the left margin after withdraw
     * must be sufficient for the open position
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function withdrawMargin(uint256 bAmount) external;
    function withdrawMargin(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Add liquidity of `bAmount` in base token
     *
     * New liquidity provider token will be issued to the provider
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function addLiquidity(uint256 bAmount) external;
    function addLiquidity(
        uint256 bAmount,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Remove `lShares` of liquidity provider token
     *
     * The liquidity provider token will be burned and
     * the corresponding amount in base token will be sent to provider
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function removeLiquidity(uint256 lShares) external;
    function removeLiquidity(
        uint256 lShares,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Liquidate the position owned by `owner`
     * Anyone can call this function to liquidate a position, as long as the liquidation line
     * is touched, the liquidator will be rewarded
     *
     * The first version is implemented with an on-chain oracle contract
     * The second version is implemented with off-chain price provider with signature
     */
    function liquidate(address owner) external;
    function liquidate(
        address owner,
        uint256 timestamp,
        uint256 price,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

}

File 14 of 19: IPreMiningPool.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IMigratablePool.sol";

/**
 * @title Deri Protocol PreMining PerpetualPool Interface
 */
interface IPreMiningPool is IMigratablePool {

    /**
     * @dev Emitted when `owner` add liquidity of `bAmount`,
     * and receive `lShares` liquidity token
     */
    event AddLiquidity(address indexed owner, uint256 lShares, uint256 bAmount);

    /**
     * @dev Emitted when `owner` burn `lShares` of liquidity token,
     * and receive `bAmount` in base token
     */
    event RemoveLiquidity(address indexed owner, uint256 lShares, uint256 bAmount);

    /**
     * @dev Initialize pool
     *
     * addresses:
     *      bToken
     *      lToken
     *
     * parameters:
     *      minAddLiquidity
     *      redemptionFeeRatio
     */
    function initialize(
        string memory symbol_,
        address[2] calldata addresses_,
        uint256[2] calldata parameters_
    ) external;

    /**
     * @dev Returns trading symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns addresses of (bToken, pToken, lToken, oracle) in this pool
     */
    function getAddresses() external view returns (
        address bToken,
        address lToken
    );

    /**
     * @dev Returns parameters of this pool
     */
    function getParameters() external view returns (
        uint256 minAddLiquidity,
        uint256 redemptionFeeRatio
    );

    /**
     * @dev Returns currents state values of this pool
     */
    function getStateValues() external view returns (
        uint256 liquidity
    );

    /**
     * @dev Add liquidity of `bAmount` in base token
     *
     * New liquidity provider token will be issued to the provider
     */
    function addLiquidity(uint256 bAmount) external;

    /**
     * @dev Remove `lShares` of liquidity provider token
     *
     * The liquidity provider token will be burned and
     * the corresponding amount in base token will be sent to provider
     */
    function removeLiquidity(uint256 lShares) external;

}

File 15 of 19: IPToken.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC721.sol";

/**
 * @title Deri Protocol non-fungible position token interface
 */
interface IPToken is IERC721 {

    /**
     * @dev Emitted when `owner`'s position is updated
     */
    event Update(
        address indexed owner,
        int256 volume,
        int256 cost,
        int256 lastCumuFundingRate,
        uint256 margin,
        uint256 lastUpdateTimestamp
    );

    /**
     * @dev Position struct
     */
    struct Position {
        // Position volume, long is positive and short is negative
        int256 volume;
        // Position cost, long position cost is positive, short position cost is negative
        int256 cost;
        // The last cumuFundingRate since last funding settlement for this position
        // The overflow for this value is intended
        int256 lastCumuFundingRate;
        // Margin associated with this position
        uint256 margin;
        // Last timestamp this position updated
        uint256 lastUpdateTimestamp;
    }

    /**
     * @dev Set pool address of position token
     * pool is the only controller of this contract
     * can only be called by current pool
     */
    function setPool(address newPool) external;

    /**
     * @dev Returns address of current pool
     */
    function pool() external view returns (address);

    /**
     * @dev Returns the token collection name
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the total number of ever minted position tokens, including those burned
     */
    function totalMinted() external view returns (uint256);

    /**
     * @dev Returns the total number of existent position tokens
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns if `owner` owns a position token in this contract
     */
    function exists(address owner) external view returns (bool);

    /**
     * @dev Returns if position token of `tokenId` exists
     */
    function exists(uint256 tokenId) external view returns (bool);

    /**
     * @dev Returns the position of owner `owner`
     *
     * `owner` must exist
     */
    function getPosition(address owner) external view returns (
        int256 volume,
        int256 cost,
        int256 lastCumuFundingRate,
        uint256 margin,
        uint256 lastUpdateTimestamp
    );

    /**
     * @dev Returns the position of token `tokenId`
     *
     * `tokenId` must exist
     */
    function getPosition(uint256 tokenId) external view returns (
        int256 volume,
        int256 cost,
        int256 lastCumuFundingRate,
        uint256 margin,
        uint256 lastUpdateTimestamp
    );

    /**
     * @dev Mint a position token for `owner` with intial margin of `margin`
     *
     * Can only be called by pool
     * `owner` cannot be zero address
     * `owner` must not exist before calling
     */
    function mint(address owner, uint256 margin) external;

    /**
     * @dev Update the position token for `owner`
     *
     * Can only be called by pool
     * `owner` must exist
     */
    function update(
        address owner,
        int256 volume,
        int256 cost,
        int256 lastCumuFundingRate,
        uint256 margin,
        uint256 lastUpdateTimestamp
    ) external;

    /**
     * @dev Burn the position token owned of `owner`
     *
     * Can only be called by pool
     * `owner` must exist
     */
    function burn(address owner) external;

}

File 16 of 19: MigratablePool.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IMigratablePool.sol";

/**
 * @dev Deri Protocol migratable pool implementation
 */
abstract contract MigratablePool is IMigratablePool {

    // Controller address
    address _controller;

    // Migration timestamp of this pool, zero means not set
    // Migration timestamp can only be set with a grace period at least 3 days, and the
    // `migrationDestination` pool address must be also set when setting migration timestamp,
    // users can use this grace period to verify the `migrationDestination` pool code
    uint256 _migrationTimestamp;

    // The new pool this pool will migrate to after grace period, zero address means not set
    address _migrationDestination;

    modifier _controller_() {
        require(msg.sender == _controller, "can only be called by current controller");
        _;
    }

    /**
     * @dev See {IMigratablePool}.{setController}
     */
    function setController(address newController) public override {
        require(newController != address(0), "MigratablePool: setController to 0 address");
        require(
            _controller == address(0) || msg.sender == _controller,
            "MigratablePool: setController can only be called by current controller or not set"
        );
        _controller = newController;
    }

    /**
     * @dev See {IMigratablePool}.{controller}
     */
    function controller() public view override returns (address) {
        return _controller;
    }

    /**
     * @dev See {IMigratablePool}.{migrationTimestamp}
     */
    function migrationTimestamp() public view override returns (uint256) {
        return _migrationTimestamp;
    }

    /**
     * @dev See {IMigratablePool}.{migrationDestination}
     */
    function migrationDestination() public view override returns (address) {
        return _migrationDestination;
    }

    /**
     * @dev See {IMigratablePool}.{prepareMigration}
     */
    function prepareMigration(address newPool, uint256 graceDays) public override _controller_ {
        require(newPool != address(0), "MigratablePool: prepareMigration to 0 address");
        require(graceDays >= 3 && graceDays <= 365, "MigratablePool: graceDays must be 3-365 days");

        _migrationTimestamp = block.timestamp + graceDays * 1 days;
        _migrationDestination = newPool;

        emit PrepareMigration(_migrationTimestamp, address(this), _migrationDestination);
    }

    /**
     * @dev See {IMigratablePool}.{approveMigration}
     *
     * This function will be implemented in inheriting contract
     * This function will change if there is an upgrade to existent pool
     */
    // function approveMigration() public virtual override _controller_ {}

    /**
     * @dev See {IMigratablePool}.{executeMigration}
     *
     * This function will be implemented in inheriting contract
     * This function will change if there is an upgrade to existent pool
     */
    // function executeMigration(address source) public virtual override _controller_ {}

}

File 17 of 19: MixedSafeMathWithUnit.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title Mixed safe math with base unit of 10**18
 */
library MixedSafeMathWithUnit {

    uint256 constant UONE = 10**18;
    uint256 constant UMAX = 2**255 - 1;

    int256 constant IONE = 10**18;
    int256 constant IMIN = -2**255;

    //================================================================================
    // Conversions
    //================================================================================

    /**
     * @dev Convert uint256 to int256
     */
    function utoi(uint256 a) internal pure returns (int256) {
        require(a <= UMAX, "MixedSafeMathWithUnit: convert uint256 to int256 overflow");
        int256 b = int256(a);
        return b;
    }

    /**
     * @dev Convert int256 to uint256
     */
    function itou(int256 a) internal pure returns (uint256) {
        require(a >= 0, "MixedSafeMathWithUnit: convert int256 to uint256 overflow");
        uint256 b = uint256(a);
        return b;
    }

    /**
     * @dev Take abs of int256
     */
    function abs(int256 a) internal pure returns (int256) {
        require(a != IMIN, "MixedSafeMathWithUnit: int256 abs overflow");
        if (a >= 0) {
            return a;
        } else {
            return -a;
        }
    }

    /**
     * @dev Take negation of int256
     */
    function neg(int256 a) internal pure returns (int256) {
        require(a != IMIN, "MixedSafeMathWithUnit: int256 negate overflow");
        return -a;
    }

    //================================================================================
    // Rescale and reformat
    //================================================================================

    function _rescale(uint256 a, uint256 decimals1, uint256 decimals2)
        internal pure returns (uint256)
    {
        uint256 scale1 = 10 ** decimals1;
        uint256 scale2 = 10 ** decimals2;
        uint256 b = a * scale2;
        require(b / scale2 == a, "MixedSafeMathWithUnit: rescale uint256 overflow");
        uint256 c = b / scale1;
        return c;
    }

    function _rescale(int256 a, uint256 decimals1, uint256 decimals2)
        internal pure returns (int256)
    {
        int256 scale1 = utoi(10 ** decimals1);
        int256 scale2 = utoi(10 ** decimals2);
        int256 b = a * scale2;
        require(b / scale2 == a, "MixedSafeMathWithUnit: rescale int256 overflow");
        int256 c = b / scale1;
        return c;
    }

    /**
     * @dev Rescales a value from 10**18 base to 10**decimals base
     */
    function rescale(uint256 a, uint256 decimals) internal pure returns (uint256) {
        return _rescale(a, 18, decimals);
    }

    function rescale(int256 a, uint256 decimals) internal pure returns (int256) {
        return _rescale(a, 18, decimals);
    }

    /**
     * @dev Reformat a value to be a valid 10**decimals base value
     * The formatted value is still in 10**18 base
     */
    function reformat(uint256 a, uint256 decimals) internal pure returns (uint256) {
        return _rescale(_rescale(a, 18, decimals), decimals, 18);
    }

    function reformat(int256 a, uint256 decimals) internal pure returns (int256) {
        return _rescale(_rescale(a, 18, decimals), decimals, 18);
    }


    //================================================================================
    // Addition
    //================================================================================

    /**
     * @dev Addition: uint256 + uint256
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "MixedSafeMathWithUnit: uint256 addition overflow");
        return c;
    }

    /**
     * @dev Addition: int256 + int256
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        require(
            (b >= 0 && c >= a) || (b < 0 && c < a),
            "MixedSafeMathWithUnit: int256 addition overflow"
        );
        return c;
    }

    /**
     * @dev Addition: uint256 + int256
     * uint256(-b) will not overflow when b is IMIN
     */
    function add(uint256 a, int256 b) internal pure returns (uint256) {
        if (b >= 0) {
            return add(a, uint256(b));
        } else {
            return sub(a, uint256(-b));
        }
    }

    /**
     * @dev Addition: int256 + uint256
     */
    function add(int256 a, uint256 b) internal pure returns (int256) {
        return add(a, utoi(b));
    }

    //================================================================================
    // Subtraction
    //================================================================================

    /**
     * @dev Subtraction: uint256 - uint256
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(a >= b, "MixedSafeMathWithUnit: uint256 subtraction overflow");
        uint256 c = a - b;
        return c;
    }

    /**
     * @dev Subtraction: int256 - int256
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        require(
            (b >= 0 && c <= a) || (b < 0 && c > a),
            "MixedSafeMathWithUnit: int256 subtraction overflow"
        );
        return c;
    }

    /**
     * @dev Subtraction: uint256 - int256
     * uint256(-b) will not overflow when b is IMIN
     */
    function sub(uint256 a, int256 b) internal pure returns (uint256) {
        if (b >= 0) {
            return sub(a, uint256(b));
        } else {
            return add(a, uint256(-b));
        }
    }

    /**
     * @dev Subtraction: int256 - uint256
     */
    function sub(int256 a, uint256 b) internal pure returns (int256) {
        return sub(a, utoi(b));
    }

    //================================================================================
    // Multiplication
    //================================================================================

    /**
     * @dev Multiplication: uint256 * uint256
     */
    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, "MixedSafeMathWithUnit: uint256 multiplication overflow");
        return c / UONE;
    }

    /**
     * @dev Multiplication: int256 * int256
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        // 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;
        }
        require(!(a == -1 && b == IMIN), "MixedSafeMathWithUnit: int256 multiplication overflow");
        int256 c = a * b;
        require(c / a == b, "MixedSafeMathWithUnit: int256 multiplication overflow");
        return c / IONE;
    }

    /**
     * @dev Multiplication: uint256 * int256
     */
    function mul(uint256 a, int256 b) internal pure returns (uint256) {
        return mul(a, itou(b));
    }

    /**
     * @dev Multiplication: int256 * uint256
     */
    function mul(int256 a, uint256 b) internal pure returns (int256) {
        return mul(a, utoi(b));
    }

    //================================================================================
    // Division
    //================================================================================

    /**
     * @dev Division: uint256 / uint256
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "MixedSafeMathWithUnit: uint256 division by zero");
        uint256 c = a * UONE;
        require(
            c / UONE == a,
            "MixedSafeMathWithUnit: uint256 division internal multiplication overflow"
        );
        uint256 d = c / b;
        return d;
    }

    /**
     * @dev Division: int256 / int256
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        require(b != 0, "MixedSafeMathWithUnit: int256 division by zero");
        int256 c = a * IONE;
        require(
            c / IONE == a,
            "MixedSafeMathWithUnit: int256 division internal multiplication overflow"
        );
        require(!(c == IMIN && b == -1), "MixedSafeMathWithUnit: int256 division overflow");
        int256 d = c / b;
        return d;
    }

    /**
     * @dev Division: uint256 / int256
     */
    function div(uint256 a, int256 b) internal pure returns (uint256) {
        return div(a, itou(b));
    }

    /**
     * @dev Division: int256 / uint256
     */
    function div(int256 a, uint256 b) internal pure returns (int256) {
        return div(a, utoi(b));
    }

}

File 18 of 19: SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

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

File 19 of 19: UnsignedSafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title Unsigned safe math
 */
library UnsignedSafeMath {

    /**
     * @dev Addition of unsigned integers, counterpart to `+`
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "UnsignedSafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Subtraction of unsigned integers, counterpart to `-`
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(a >= b, "UnsignedSafeMath: subtraction overflow");
        uint256 c = a - b;
        return c;
    }

    /**
     * @dev Multiplication of unsigned integers, counterpart to `*`
     */
    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, "UnsignedSafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Division of unsigned integers, counterpart to `/`
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "UnsignedSafeMath: division by zero");
        uint256 c = a / b;
        return c;
    }

    /**
     * @dev Modulo of unsigned integers, counterpart to `%`
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "UnsignedSafeMath: modulo by zero");
        uint256 c = a % b;
        return c;
    }

}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"lShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"DepositMargin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"migrationTimestamp","type":"uint256"},{"indexed":false,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"ExecuteMigration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"int256","name":"volume","type":"int256"},{"indexed":false,"internalType":"int256","name":"cost","type":"int256"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"migrationTimestamp","type":"uint256"},{"indexed":false,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"PrepareMigration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"lShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"int256","name":"tradeVolume","type":"int256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Trade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"WithdrawMargin","type":"event"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approveMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"depositMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"source","type":"address"}],"name":"executeMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAddresses","outputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"pToken","type":"address"},{"internalType":"address","name":"lToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"liquidatorQualifier","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getParameters","outputs":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint256","name":"feeRatio","type":"uint256"},{"internalType":"uint256","name":"minPoolMarginRatio","type":"uint256"},{"internalType":"uint256","name":"minInitialMarginRatio","type":"uint256"},{"internalType":"uint256","name":"minMaintenanceMarginRatio","type":"uint256"},{"internalType":"uint256","name":"minAddLiquidity","type":"uint256"},{"internalType":"uint256","name":"redemptionFeeRatio","type":"uint256"},{"internalType":"uint256","name":"fundingRateCoefficient","type":"uint256"},{"internalType":"uint256","name":"minLiquidationReward","type":"uint256"},{"internalType":"uint256","name":"maxLiquidationReward","type":"uint256"},{"internalType":"uint256","name":"liquidationCutRatio","type":"uint256"},{"internalType":"uint256","name":"priceDelayAllowance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStateValues","outputs":[{"internalType":"int256","name":"cumuFundingRate","type":"int256"},{"internalType":"uint256","name":"cumuFundingRateBlock","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"int256","name":"tradersNetVolume","type":"int256"},{"internalType":"int256","name":"tradersNetCost","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address[5]","name":"addresses_","type":"address[5]"},{"internalType":"uint256[12]","name":"parameters_","type":"uint256[12]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrationDestination","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPool","type":"address"},{"internalType":"uint256","name":"graceDays","type":"uint256"}],"name":"prepareMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lShares","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lShares","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"tradeVolume","type":"int256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"trade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"tradeVolume","type":"int256"}],"name":"trade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"tradeVolume","type":"int256"},{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"tradeWithMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"tradeVolume","type":"int256"},{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"tradeWithMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"}],"name":"withdrawMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bAmount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"withdrawMargin","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Block Transaction Gas Used Reward
Age Block Fee Address Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading