Contract 0xbb766D634E93522533917C95e75B052900416f5a

Txn Hash Method
Block
From
To
Value [Txn Fee]
0x4e211001ab0b52a3ea8a90b82c85591e205d3a2b5ec118f45e410936fbc5c9170x60c06040182910452022-08-06 13:31:0111 days 17 hrs ago0xf5c8e1eaffd278a383c13061b4980db7619479af IN  Create: AMM0 AVAX0.‍12066647525
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AMM

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : AMM.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";

import { Governable } from "./legos/Governable.sol";
import { ERC20Detailed, IOracle, IRegistry, IVAMM, IAMM, IClearingHouse } from "./Interfaces.sol";

contract AMM is IAMM, Governable {
    using SafeCast for uint256;
    using SafeCast for int256;

    uint256 public constant spotPriceTwapInterval = 1 hours;
    uint256 public constant fundingPeriod = 1 hours;
    int256 constant BASE_PRECISION = 1e18;

    address public immutable clearingHouse;
    uint256 public immutable unbondRoundOff;

    /* ****************** */
    /*       Storage      */
    /* ****************** */

    // System-wide config

    IOracle public oracle;

    // AMM config

    IVAMM override public vamm;
    address override public underlyingAsset;
    string public name;

    uint256 public fundingBufferPeriod;
    uint256 public nextFundingTime;
    int256 public cumulativePremiumFraction;
    int256 public cumulativePremiumPerDtoken;
    int256 public posAccumulator;

    uint256 public longOpenInterestNotional;
    uint256 public shortOpenInterestNotional;
    uint256 public maxOracleSpreadRatio; // scaled 2 decimals
    uint256 public maxLiquidationRatio; // scaled 2 decimals
    uint256 public maxLiquidationPriceSpread; // scaled 6 decimals

    enum Side { LONG, SHORT }
    struct Position {
        int256 size;
        uint256 openNotional;
        int256 lastPremiumFraction;
        uint liquidationThreshold;
    }
    mapping(address => Position) override public positions;

    mapping(address => Maker) internal _makers;
    uint256 public withdrawPeriod;
    uint256 public unbondPeriod;

    struct ReserveSnapshot {
        uint256 lastPrice;
        uint256 timestamp;
        uint256 blockNumber;
        bool isLiquidation;
    }
    ReserveSnapshot[] public reserveSnapshots;

    Ignition override public ignition;
    IAMM.AMMState override public ammState;

    /// @notice Min amount of base asset quantity to trade or add liquidity for
    uint256 public minSizeRequirement;

    struct VarGroup1 {
        uint minQuote;
        uint minBase;
        bool isLiquidation;
    }

    uint256[50] private __gap;

    /* ****************** */
    /*       Events       */
    /* ****************** */

    // Generic AMM related events
    event FundingRateUpdated(int256 premiumFraction, uint256 underlyingPrice, int256 cumulativePremiumFraction, int256 cumulativePremiumPerDtoken, int256 posAccumulator, uint256 nextFundingTime, uint256 timestamp, uint256 blockNumber);
    event FundingPaid(address indexed trader, int256 takerFundingPayment, int256 makerFundingPayment);
    event Swap(uint256 lastPrice, uint256 openInterestNotional);

    // Trader related events
    event PositionChanged(address indexed trader, int256 size, uint256 openNotional, int256 realizedPnl);
    event LiquidityAdded(address indexed trader, uint dToken, uint baseAsset, uint quoteAsset, uint timestamp);
    event LiquidityRemoved(address indexed trader, uint dToken, uint baseAsset, uint quoteAsset, int256 realizedPnl, bool isLiquidation, uint timestamp);
    event Unbonded(address indexed trader, uint256 unbondAmount, uint256 unbondTime, uint timestamp);

    /**
    * @dev This is only emitted when maker funding related events are updated.
    * These fields are: ignition,dToken,lastPremiumFraction,pos,lastPremiumPerDtoken,posAccumulator
    */
    event MakerPositionChanged(address indexed trader, Maker maker, uint timestamp);

    modifier onlyClearingHouse() {
        require(msg.sender == clearingHouse, "Only clearingHouse");
        _;
    }

    modifier onlyVamm() {
        require(msg.sender == address(vamm), "Only VAMM");
        _;
    }

    modifier whenIgnition() {
        require(ammState == AMMState.Ignition, "amm_not_ignition");
        _;
    }

    modifier whenActive() {
        require(ammState == AMMState.Active, "amm_not_active");
        _;
    }

    constructor(address _clearingHouse, uint _unbondRoundOff) {
        clearingHouse = _clearingHouse;
        unbondRoundOff = _unbondRoundOff;
    }

    function initialize(
        string memory _name,
        address _underlyingAsset,
        address _oracle,
        uint _minSizeRequirement,
        address _vamm,
        address _governance
    ) external initializer {
        name = _name;
        underlyingAsset = _underlyingAsset;
        oracle = IOracle(_oracle);
        minSizeRequirement = _minSizeRequirement;
        vamm = IVAMM(_vamm);
        _setGovernace(_governance);

        // values that most likely wouldn't need to change frequently
        fundingBufferPeriod = 15 minutes;
        withdrawPeriod = 1 days;
        maxOracleSpreadRatio = 20;
        unbondPeriod = 3 days;
        maxLiquidationRatio = 25;
        maxLiquidationPriceSpread = 1e6;
    }

    /**
    * @dev baseAssetQuantity != 0 has been validated in clearingHouse._openPosition()
    */
    function openPosition(address trader, int256 baseAssetQuantity, uint quoteAssetLimit)
        override
        external
        onlyClearingHouse
        whenActive
        returns (int realizedPnl, uint quoteAsset, bool isPositionIncreased)
    {
        Position memory position = positions[trader];
        bool isNewPosition = position.size == 0 ? true : false;
        Side side = baseAssetQuantity > 0 ? Side.LONG : Side.SHORT;
        if (isNewPosition || (position.size > 0 ? Side.LONG : Side.SHORT) == side) {
            // realizedPnl = 0;
            quoteAsset = _increasePosition(trader, baseAssetQuantity, quoteAssetLimit);
            isPositionIncreased = true;
        } else {
            (realizedPnl, quoteAsset, isPositionIncreased) = _openReversePosition(trader, baseAssetQuantity, quoteAssetLimit);
        }

        uint totalPosSize = uint(abs(positions[trader].size));
        require(totalPosSize == 0 || totalPosSize >= minSizeRequirement, "position_less_than_minSize");
        // update liquidation thereshold
        positions[trader].liquidationThreshold = Math.max(
            totalPosSize * maxLiquidationRatio / 100,
            minSizeRequirement
        );

        _emitPositionChanged(trader, realizedPnl);
    }

    function liquidatePosition(address trader)
        override
        external
        onlyClearingHouse
        returns (int realizedPnl, uint quoteAsset)
    {
        // don't need an ammState check because there should be no active positions
        Position memory position = positions[trader];
        bool isLongPosition = position.size > 0 ? true : false;
        uint positionToLiquidate = Math.min(uint(abs(position.size)), position.liquidationThreshold);

        // liquidation price safeguard
        // price before liquidaiton should be within X% range of last liquidation price in the same block or previous block price
        uint index = reserveSnapshots.length - 1;
        uint lastTradePrice = reserveSnapshots[index].lastPrice;
        while(reserveSnapshots[index].blockNumber == block.number && index != 0) {
            if (reserveSnapshots[index].isLiquidation) {
                lastTradePrice = reserveSnapshots[index].lastPrice;
                break;
            }
            index -= 1;
            lastTradePrice = reserveSnapshots[index].lastPrice;
        }

        uint diff = lastPrice();
        if (diff >= lastTradePrice) {
            diff -= lastTradePrice;
        } else {
            diff = lastTradePrice - diff;
        }
        require(diff <= lastTradePrice * maxLiquidationPriceSpread / 1e8, "AMM.liquidation_price_slippage");

        // liquidate position
        if (isLongPosition) {
            (realizedPnl, quoteAsset) = _reducePosition(trader, -positionToLiquidate.toInt256(), 0, true /* isLiquidation */);
        } else {
            (realizedPnl, quoteAsset) = _reducePosition(trader, positionToLiquidate.toInt256(), type(uint).max, true /* isLiquidation */);
        }
        _emitPositionChanged(trader, realizedPnl);
    }

    function updatePosition(address trader)
        override
        external
        onlyClearingHouse
        returns(int256 fundingPayment)
    {
        if (ammState != AMMState.Active) return 0;

        _setIgnitionShare(trader);
        Maker storage maker = _makers[trader];
        int256 takerFundingPayment;
        int256 makerFundingPayment;
        (
            takerFundingPayment,
            makerFundingPayment,
            maker.lastPremiumFraction,
            maker.lastPremiumPerDtoken
        ) = getPendingFundingPayment(trader);

        _emitMakerPositionChanged(trader);

        Position storage position = positions[trader];
        position.lastPremiumFraction = maker.lastPremiumFraction;

        // +: trader paid, -: trader received
        fundingPayment = takerFundingPayment + makerFundingPayment;
        if (fundingPayment < 0) {
            fundingPayment -= fundingPayment / 1e3; // receivers charged 0.1% to account for rounding-offs
        }
        if (fundingPayment != 0) {
            emit FundingPaid(trader, takerFundingPayment, makerFundingPayment);
        }
    }

    /* ****************** */
    /*       Makers       */
    /* ****************** */

    function addLiquidity(address maker, uint baseAssetQuantity, uint minDToken)
        override
        external
        onlyClearingHouse
        whenActive
        returns (uint dToken)
    {
        require(baseAssetQuantity >= minSizeRequirement, "adding_too_less");
        uint quoteAsset;
        uint baseAssetBal = vamm.balances(1);
        if (baseAssetBal == 0) {
            quoteAsset = baseAssetQuantity * vamm.price_scale() / 1e30;
        } else {
            quoteAsset = baseAssetQuantity * vamm.balances(0) / baseAssetBal;
        }

        dToken = vamm.add_liquidity([quoteAsset, baseAssetQuantity], minDToken);

        // updates
        Maker storage _maker = _makers[maker];
        if (_maker.dToken > 0) { // Maker only accumulates position when they had non-zero liquidity
            _maker.pos += (posAccumulator - _maker.posAccumulator) * _maker.dToken.toInt256() / 1e18;
        }
        _maker.vUSD += quoteAsset;
        _maker.vAsset += baseAssetQuantity;
        _maker.dToken += dToken;
        _maker.posAccumulator = posAccumulator;
        _emitMakerPositionChanged(maker);
        emit LiquidityAdded(maker, dToken, baseAssetQuantity, quoteAsset, _blockTimestamp());
    }

    /**
    * @notice Express the intention to withdraw liquidity.
    * Can only withdraw after unbondPeriod and within withdrawal period
    * All withdrawals are batched together to 00:00 GMT
    * @param dToken Amount of dToken to withdraw
    */
    function unbondLiquidity(uint dToken) external whenActive {
        address maker = msg.sender;
        // this needs to be invoked here because updatePosition is not called before unbondLiquidity
        _setIgnitionShare(maker);
        _emitMakerPositionChanged(maker); // because dToken was updated

        Maker storage _maker = _makers[maker];
        require(dToken != 0, "unbonding_0");
        require(_maker.dToken >= dToken, "unbonding_too_much");
        _maker.unbondAmount = dToken;
        _maker.unbondTime = ((_blockTimestamp() + unbondPeriod) / unbondRoundOff) * unbondRoundOff;
        emit Unbonded(maker, dToken, _maker.unbondTime, _blockTimestamp());
    }

    function forceRemoveLiquidity(address maker)
        override
        external
        onlyClearingHouse
        returns (int realizedPnl, uint makerOpenNotional, int makerPosition)
    {
        Maker storage _maker = _makers[maker];
        if (ammState == AMMState.Active) {
            // @todo partial liquidations and slippage checks
            VarGroup1 memory varGroup1 = VarGroup1(0,0,true);
            uint dToken = _maker.dToken;
            _maker.unbondAmount -= Math.min(dToken, _maker.unbondAmount);
            return _removeLiquidity(maker, dToken, varGroup1);
        }

        // ammState == AMMState.Ignition
        ignition.quoteAsset -= _makers[maker].ignition;
        _makers[maker].ignition = 0;
        _emitMakerPositionChanged(maker);
    }

    function removeLiquidity(address maker, uint amount, uint minQuote, uint minBase)
        override
        external
        onlyClearingHouse
        returns (int realizedPnl, uint makerOpenNotional, int makerPosition)
    {
        Maker storage _maker = _makers[maker];
        require(_maker.unbondAmount >= amount, "withdrawing_more_than_unbonded");
        unchecked { _maker.unbondAmount -= amount; }
        uint _now = _blockTimestamp();
        require(_now >= _maker.unbondTime, "still_unbonding");
        require(_now <= _maker.unbondTime + withdrawPeriod, "withdraw_period_over");
        // there's no need to reset the unbondTime, unbondAmount will take care of everything
        VarGroup1 memory varGroup1 = VarGroup1(minQuote, minBase, false);
        (realizedPnl, makerOpenNotional, makerPosition) = _removeLiquidity(maker, amount, varGroup1);
        if (_maker.dToken != 0) {
            // if the maker doesn't remove all their liq, ensure decent size
            require(_maker.vAsset >= minSizeRequirement, "leftover_liquidity_is_too_less");
            uint totalPosSize = uint(abs(positions[maker].size));
            require(totalPosSize == 0 || totalPosSize >= minSizeRequirement, "removing_very_small_liquidity");
        }
    }

    function _removeLiquidity(address maker, uint amount, VarGroup1 memory varGroup1)
        internal
        returns (int realizedPnl, uint makerOpenNotional, int makerPosition)
    {
        Maker storage _maker = _makers[maker];
        Position storage position = positions[maker];

        // amount <= _maker.dToken will be asserted when updating maker.dToken
        uint256 totalOpenNotional;
        uint[2] memory dBalances = [uint(0),uint(0)];
        (
            makerPosition,
            makerOpenNotional,
            totalOpenNotional,
            realizedPnl, // feeAdjustedPnl
            dBalances
        ) = vamm.remove_liquidity(
            amount,
            [varGroup1.minQuote, varGroup1.minBase],
            _maker.vUSD,
            _maker.vAsset,
            _maker.dToken,
            position.size,
            position.openNotional
        );

        // update maker info
        {
            uint diff = _maker.dToken - amount;
            if (diff == 0) {
                _maker.pos = 0;
                _maker.vAsset = 0;
                _maker.vUSD = 0;
                _maker.dToken = 0;
            } else {
                // muitiply by diff because a taker position will also be opened while removing liquidity and its funding payment is calculated seperately
                _maker.pos = _maker.pos + (posAccumulator - _maker.posAccumulator) * diff.toInt256() / 1e18;
                _maker.vAsset = _maker.vAsset * diff / _maker.dToken;
                _maker.vUSD = _maker.vUSD * diff / _maker.dToken;
                _maker.dToken = diff;
            }
            _maker.posAccumulator = posAccumulator;
        }

        // translate impermanent position to a permanent one
        {
            if (makerPosition != 0) {
                // reducing or reversing position
                if (makerPosition * position.size < 0) { // this ensures takerPosition !=0
                    realizedPnl += _getPnlWhileReducingPosition(position.size, position.openNotional, makerPosition);
                }
                position.openNotional = totalOpenNotional;
                position.size += makerPosition;

                // update liquidation thereshold
                position.liquidationThreshold = Math.max(
                    uint(abs(position.size)) * maxLiquidationRatio / 100,
                    minSizeRequirement
                );

                // update long and short open interest notional
                if (makerPosition > 0) {
                    longOpenInterestNotional += makerPosition.toUint256();
                } else {
                    shortOpenInterestNotional += (-makerPosition).toUint256();
                }

                // these events will enable the parsing logic in the indexer to work seamlessly
                emit Swap(lastPrice(), openInterestNotional());
                _emitPositionChanged(maker, realizedPnl);
            }
        }

        _emitMakerPositionChanged(maker);
        emit LiquidityRemoved(
            maker,
            amount,
            dBalances[1], // baseAsset
            dBalances[0], // quoteAsset
            realizedPnl,
            varGroup1.isLiquidation,
            _blockTimestamp()
        );
    }

    function getOpenNotionalWhileReducingPosition(
        int256 positionSize,
        uint256 newNotionalPosition,
        int256 unrealizedPnl,
        int256 baseAssetQuantity
    )
        override
        public
        pure
        returns(uint256 remainOpenNotional, int realizedPnl)
    {
        require(abs(positionSize) >= abs(baseAssetQuantity), "AMM.ONLY_REDUCE_POS");
        bool isLongPosition = positionSize > 0 ? true : false;

        realizedPnl = unrealizedPnl * abs(baseAssetQuantity) / abs(positionSize);
        int256 unrealizedPnlAfter = unrealizedPnl - realizedPnl;

        /**
        * We need to determine the openNotional value of the reduced position now.
        * We know notionalPosition and unrealizedPnlAfter (unrealizedPnl times the ratio of open position)
        * notionalPosition = notionalPosition - quoteAsset (exchangedQuoteAssetAmount)
        * calculate openNotional (it's different depends on long or short side)
        * long: unrealizedPnl = notionalPosition - openNotional => openNotional = notionalPosition - unrealizedPnl
        * short: unrealizedPnl = openNotional - notionalPosition => openNotional = notionalPosition + unrealizedPnl
        */
        if (isLongPosition) {
            /**
            * Let baseAssetQuantity = Q, position.size = size, by definition of _reducePosition, abs(size) >= abs(Q)
            * quoteAsset = notionalPosition * Q / size
            * unrealizedPnlAfter = unrealizedPnl - realizedPnl = unrealizedPnl - unrealizedPnl * Q / size
            * remainOpenNotional = notionalPosition - notionalPosition * Q / size - unrealizedPnl + unrealizedPnl * Q / size
            * => remainOpenNotional = notionalPosition(size-Q)/size - unrealizedPnl(size-Q)/size
            * => remainOpenNotional = (notionalPosition - unrealizedPnl) * (size-Q)/size
            * Since notionalPosition includes the PnL component, notionalPosition >= unrealizedPnl and size >= Q
            * Hence remainOpenNotional >= 0
            */
            remainOpenNotional = (newNotionalPosition.toInt256() - unrealizedPnlAfter).toUint256();  // will assert that remainOpenNotional >= 0
        } else {
            /**
            * Let baseAssetQuantity = Q, position.size = size, by definition of _reducePosition, abs(size) >= abs(Q)
            * quoteAsset = notionalPosition * Q / size
            * unrealizedPnlAfter = unrealizedPnl - realizedPnl = unrealizedPnl - unrealizedPnl * Q / size
            * remainOpenNotional = notionalPosition - notionalPosition * Q / size + unrealizedPnl - unrealizedPnl * Q / size
            * => remainOpenNotional = notionalPosition(size-Q)/size + unrealizedPnl(size-Q)/size
            * => remainOpenNotional = (notionalPosition + unrealizedPnl) * (size-Q)/size
            * => In AMM.sol, unrealizedPnl = position.openNotional - notionalPosition
            * => notionalPosition + unrealizedPnl >= 0
            * Hence remainOpenNotional >= 0
            */
            remainOpenNotional = (newNotionalPosition.toInt256() + unrealizedPnlAfter).toUint256();  // will assert that remainOpenNotional >= 0
        }
    }

    /**
     * @notice update funding rate
     * @dev only allow to update while reaching `nextFundingTime`
     */
    function settleFunding()
        override
        external
        onlyClearingHouse
    {
        if (
            ammState != AMMState.Active
            || _blockTimestamp() < nextFundingTime
        ) return;

        // premium = twapMarketPrice - twapIndexPrice
        // timeFraction = fundingPeriod(1 hour) / 1 day
        // premiumFraction = premium * timeFraction
        int256 underlyingPrice = getUnderlyingTwapPrice(spotPriceTwapInterval);
        int256 premium = getTwapPrice(spotPriceTwapInterval) - underlyingPrice;
        int256 premiumFraction = (premium * int256(fundingPeriod)) / 1 days;

        int256 premiumPerDtoken = posAccumulator * premiumFraction;

        // makers pay slightly more to account for rounding off
        premiumPerDtoken = (premiumPerDtoken / BASE_PRECISION) + 1;

        cumulativePremiumFraction += premiumFraction;
        cumulativePremiumPerDtoken += premiumPerDtoken;

        // Updates for next funding event
        // in order to prevent multiple funding settlement during very short time after network congestion
        uint256 minNextValidFundingTime = _blockTimestamp() + fundingBufferPeriod;

        // floor((nextFundingTime + fundingPeriod) / 3600) * 3600
        uint256 nextFundingTimeOnHourStart = ((nextFundingTime + fundingPeriod) / 1 hours) * 1 hours;

        // max(nextFundingTimeOnHourStart, minNextValidFundingTime)
        nextFundingTime = nextFundingTimeOnHourStart > minNextValidFundingTime
            ? nextFundingTimeOnHourStart
            : minNextValidFundingTime;

        _emitFundingRateUpdated(premiumFraction, underlyingPrice);
    }

    function commitLiquidity(address maker, uint quoteAsset)
        override
        external
        whenIgnition
        onlyClearingHouse
    {
        quoteAsset /= 2; // only need to track the USD side
        _makers[maker].ignition += quoteAsset;
        ignition.quoteAsset += quoteAsset;
        _emitMakerPositionChanged(maker);
    }

    function liftOff() external onlyGovernance whenIgnition {
        uint256 underlyingPrice = getUnderlyingTwapPrice(15 minutes).toUint256();
        require(underlyingPrice > 0, "amm.liftOff.underlyingPrice_not_set");
        vamm.setinitialPrice(underlyingPrice * 1e12); // vamm expects 18 decimal scale
        if (ignition.quoteAsset > 0) {
            ignition.baseAsset = ignition.quoteAsset * 1e18 / underlyingPrice;
            ignition.dToken = vamm.add_liquidity([ignition.quoteAsset, ignition.baseAsset], 0);

            // helps in the API logic
            emit LiquidityAdded(address(this), ignition.dToken, ignition.baseAsset, ignition.quoteAsset, _blockTimestamp());
        }

        ammState = AMMState.Active;
        // funding games can now begin
        nextFundingTime = ((_blockTimestamp() + fundingPeriod) / 1 hours) * 1 hours;
    }

    function _setIgnitionShare(address maker) internal {
        uint vUSD = _makers[maker].ignition;
        if (vUSD == 0) return;

        Maker storage _maker = _makers[maker];
        _maker.vUSD = vUSD;
        (_maker.vAsset, _maker.dToken) = getIgnitionShare(vUSD);
        _maker.ignition = 0;
    }

    function getIgnitionShare(uint vUSD) override public view returns (uint vAsset, uint dToken) {
        vAsset = ignition.baseAsset * vUSD / ignition.quoteAsset;
        dToken = ignition.dToken * vUSD / ignition.quoteAsset;
    }

    // View

    function getSnapshotLen() external view returns (uint256) {
        return reserveSnapshots.length;
    }

    function getUnderlyingTwapPrice(uint256 _intervalInSeconds) public view returns (int256) {
        return oracle.getUnderlyingTwapPrice(underlyingAsset, _intervalInSeconds);
    }

    function getTwapPrice(uint256 _intervalInSeconds) public view returns (int256) {
        return _calcTwap(_intervalInSeconds).toInt256();
    }

    function getNotionalPositionAndUnrealizedPnl(address trader)
        override
        external
        view
        returns(uint256 notionalPosition, int256 unrealizedPnl, int256 size, uint256 openNotional)
    {
        if (ammState == AMMState.Ignition) {
            return (_makers[trader].ignition * 2, 0, 0, 0);
        }

        uint vUSD = _makers[trader].ignition;
        uint vAsset;
        uint dToken;
        if (vUSD > 0) { // participated in ignition
            (vAsset, dToken) = getIgnitionShare(vUSD);
        } else {
            vUSD = _makers[trader].vUSD;
            vAsset = _makers[trader].vAsset;
            dToken = _makers[trader].dToken;
        }

        (notionalPosition, size, unrealizedPnl, openNotional) = vamm.get_notional(
            dToken,
            vUSD,
            vAsset,
            positions[trader].size,
            positions[trader].openNotional
        );
    }

    /**
    * @notice returns false if
    * (1-maxSpreadRatio)*indexPrice < markPrice < (1+maxSpreadRatio)*indexPrice
    * else, true
    */
    function isOverSpreadLimit() external view returns(bool) {
        if (ammState != AMMState.Active) return false;

        uint oraclePrice = uint(oracle.getUnderlyingPrice(underlyingAsset));
        uint markPrice = lastPrice();
        uint oracleSpreadRatioAbs;
        if (markPrice > oraclePrice) {
            oracleSpreadRatioAbs = markPrice - oraclePrice;
        } else {
            oracleSpreadRatioAbs = oraclePrice - markPrice;
        }
        oracleSpreadRatioAbs = oracleSpreadRatioAbs * 100 / oraclePrice;

        if (oracleSpreadRatioAbs >= maxOracleSpreadRatio) {
            return true;
        }
        return false;
    }

    /**
    * @notice returns notionalPosition and unrealizedPnl when isOverSpreadLimit()
    * calculate margin fraction using markPrice and oraclePrice
    * if mode = Maintenance_Margin, return values which have maximum margin fraction
    * if mode = min_allowable_margin, return values which have minimum margin fraction
    */
    function getOracleBasedPnl(address trader, int256 margin, IClearingHouse.Mode mode) override external view returns (uint notionalPosition, int256 unrealizedPnl) {
        Maker memory _maker = _makers[trader];
        if (ammState == AMMState.Ignition) {
            return (_maker.ignition * 2, 0);
        }

        Position memory _taker = positions[trader];
        int256 size;
        uint openNotional;
        (notionalPosition, size, unrealizedPnl, openNotional) = vamm.get_notional(
            _maker.dToken,
            _maker.vUSD,
            _maker.vAsset,
            _taker.size,
            _taker.openNotional
        );

        if (notionalPosition == 0) {
            return (0, 0);
        }

        int256 marginFraction = (margin + unrealizedPnl) * 1e6 / notionalPosition.toInt256();
        (int oracleBasedNotional, int256 oracleBasedUnrealizedPnl, int256 oracleBasedMF) = _getOracleBasedMarginFraction(
            trader,
            margin,
            openNotional,
            size
        );

        if (mode == IClearingHouse.Mode.Maintenance_Margin) {
            if (oracleBasedMF > marginFraction) {
                notionalPosition = oracleBasedNotional.toUint256();
                unrealizedPnl = oracleBasedUnrealizedPnl;
            }
        } else if (oracleBasedMF < marginFraction) { // IClearingHouse.Mode.Min_Allowable_Margin
            notionalPosition = oracleBasedNotional.toUint256();
            unrealizedPnl = oracleBasedUnrealizedPnl;
        }
    }

    function _getOracleBasedMarginFraction(address trader, int256 margin, uint256 openNotional, int256 size)
        internal
        view
        returns (int oracleBasedNotional, int256 oracleBasedUnrealizedPnl, int256 marginFraction)
    {
        int256 oraclePrice = oracle.getUnderlyingPrice(underlyingAsset);
        oracleBasedNotional = oraclePrice * abs(size) / BASE_PRECISION;
        if (size > 0) {
            oracleBasedUnrealizedPnl = oracleBasedNotional - openNotional.toInt256();
        } else if (size < 0) {
            oracleBasedUnrealizedPnl = openNotional.toInt256() - oracleBasedNotional;
        }
        // notionalPostion = max(makerDebt, makerPositionNotional) + takerPositionalNotional
        // = max(makerDebt + takerPositionNotional, makerPositionNotional + takerPositionNotional)
        int256 oracleBasedTakerNotional = oraclePrice * abs(positions[trader].size) / BASE_PRECISION;
        oracleBasedNotional = _max(2 * _makers[trader].vUSD.toInt256() + oracleBasedTakerNotional, oracleBasedNotional);
        marginFraction = (margin + oracleBasedUnrealizedPnl) * 1e6 / oracleBasedNotional;
    }

    function getPendingFundingPayment(address trader)
        override
        public
        view
        returns(
            int256 takerFundingPayment,
            int256 makerFundingPayment,
            int256 latestCumulativePremiumFraction,
            int256 latestPremiumPerDtoken
        )
    {
        Position memory taker = positions[trader];
        Maker memory maker = _makers[trader];

        // cache state variables locally for cheaper access and return values
        latestCumulativePremiumFraction = cumulativePremiumFraction;
        latestPremiumPerDtoken = cumulativePremiumPerDtoken;

        // Taker
        takerFundingPayment = (latestCumulativePremiumFraction - taker.lastPremiumFraction)
            * taker.size
            / BASE_PRECISION;

        // Maker
        uint256 dToken;
        uint vUSD = _makers[trader].ignition;
        if (vUSD > 0) {
            (,dToken) = getIgnitionShare(vUSD);
        } else {
            dToken = maker.dToken;
        }

        if (dToken > 0) {
            int256 cpf = latestCumulativePremiumFraction - maker.lastPremiumFraction;
            makerFundingPayment = (
                maker.pos * cpf +
                (
                    latestPremiumPerDtoken
                    - maker.lastPremiumPerDtoken
                    - maker.posAccumulator * cpf / BASE_PRECISION
                ) * dToken.toInt256()
            ) / BASE_PRECISION;
        }
    }

    function getCloseQuote(int256 baseAssetQuantity) override public view returns(uint256 quoteAssetQuantity) {
        if (baseAssetQuantity > 0) {
            return vamm.get_dy(1, 0, baseAssetQuantity.toUint256());
        } else if (baseAssetQuantity < 0) {
            return vamm.get_dx(0, 1, (-baseAssetQuantity).toUint256());
        }
        return 0;
    }

    function getTakerNotionalPositionAndUnrealizedPnl(address trader) override public view returns(uint takerNotionalPosition, int256 unrealizedPnl) {
        Position memory position = positions[trader];
        if (position.size > 0) {
            takerNotionalPosition = vamm.get_dy(1, 0, position.size.toUint256());
            unrealizedPnl = takerNotionalPosition.toInt256() - position.openNotional.toInt256();
        } else if (position.size < 0) {
            takerNotionalPosition = vamm.get_dx(0, 1, (-position.size).toUint256());
            unrealizedPnl = position.openNotional.toInt256() - takerNotionalPosition.toInt256();
        }
    }

    function lastPrice() public view returns(uint256) {
        return vamm.mark_price() / 1e12;
    }

    function openInterestNotional() public view returns (uint256) {
        return longOpenInterestNotional + shortOpenInterestNotional;
    }

    function makers(address maker) override external view returns(Maker memory) {
        return _makers[maker];
    }

    // internal

    /**
    * @dev Go long on an asset
    * @param baseAssetQuantity Exact base asset quantity to go long
    * @param max_dx Maximum amount of quote asset to be used while longing baseAssetQuantity. Lower means longing at a lower price (desirable).
    * @param isLiquidation true if liquidaiton else false
    * @return quoteAssetQuantity quote asset utilised. quoteAssetQuantity / baseAssetQuantity was the average rate.
      quoteAssetQuantity <= max_dx
    */
    function _long(int256 baseAssetQuantity, uint max_dx, bool isLiquidation) internal returns (uint256 quoteAssetQuantity) {
        require(baseAssetQuantity > 0, "VAMM._long: baseAssetQuantity is <= 0");

        uint _lastPrice;
        (quoteAssetQuantity, _lastPrice) = vamm.exchangeExactOut(
            0, // sell quote asset
            1, // purchase base asset
            baseAssetQuantity.toUint256(), // long exactly. Note that statement asserts that baseAssetQuantity >= 0
            max_dx
        ); // 6 decimals precision

        // longs not allowed if market price > (1 + maxOracleSpreadRatio)*index price
        uint256 oraclePrice = uint(oracle.getUnderlyingPrice(underlyingAsset));
        oraclePrice = oraclePrice * (100 + maxOracleSpreadRatio) / 100;
        if (!isLiquidation && _lastPrice > oraclePrice) {
            revert("VAMM._long: longs not allowed");
        }

        _addReserveSnapshot(_lastPrice, isLiquidation);
        // since maker position will be opposite of the trade
        posAccumulator -= baseAssetQuantity * 1e18 / vamm.totalSupply().toInt256();
        emit Swap(_lastPrice, openInterestNotional());
    }

    /**
    * @dev Go short on an asset
    * @param baseAssetQuantity Exact base asset quantity to short
    * @param min_dy Minimum amount of quote asset to be used while shorting baseAssetQuantity. Higher means shorting at a higher price (desirable).
    * @param isLiquidation true if liquidaiton else false
    * @return quoteAssetQuantity quote asset utilised. quoteAssetQuantity / baseAssetQuantity was the average short rate.
      quoteAssetQuantity >= min_dy.
    */
    function _short(int256 baseAssetQuantity, uint min_dy, bool isLiquidation) internal returns (uint256 quoteAssetQuantity) {
        require(baseAssetQuantity < 0, "VAMM._short: baseAssetQuantity is >= 0");

        uint _lastPrice;
        (quoteAssetQuantity, _lastPrice) = vamm.exchange(
            1, // sell base asset
            0, // get quote asset
            (-baseAssetQuantity).toUint256(), // short exactly. Note that statement asserts that baseAssetQuantity <= 0
            min_dy
        );

        // shorts not allowed if market price < (1 - maxOracleSpreadRatio)*index price
        uint256 oraclePrice = uint(oracle.getUnderlyingPrice(underlyingAsset));
        oraclePrice = oraclePrice * (100 - maxOracleSpreadRatio) / 100;
        if (!isLiquidation && _lastPrice < oraclePrice) {
            revert("VAMM._short: shorts not allowed");
        }
        _addReserveSnapshot(_lastPrice, isLiquidation);
        // since maker position will be opposite of the trade
        posAccumulator -= baseAssetQuantity * 1e18 / vamm.totalSupply().toInt256();
        emit Swap(_lastPrice, openInterestNotional());
    }

    function _emitPositionChanged(address trader, int256 realizedPnl) internal {
        Position memory position = positions[trader];
        emit PositionChanged(trader, position.size, position.openNotional, realizedPnl);
    }

    function _emitMakerPositionChanged(address maker) internal {
        emit MakerPositionChanged(maker, _makers[maker], _blockTimestamp());
    }

    /**
    * @dev Get PnL to be realized for the part of the position that is being closed
    *   Check takerPosition != 0 before calling
    */
    function _getPnlWhileReducingPosition(
        int256 takerPosition,
        uint takerOpenNotional,
        int256 makerPosition
    ) internal view returns (int256 pnlToBeRealized) {
        // notional of the combined new position
        uint newNotional = getCloseQuote(takerPosition + makerPosition);
        uint totalPosition = abs(makerPosition + takerPosition).toUint256();

        if (abs(takerPosition) > abs(makerPosition)) { // taker position side remains same
            uint reducedOpenNotional = takerOpenNotional * abs(makerPosition).toUint256() / abs(takerPosition).toUint256();
            uint makerNotional = newNotional * abs(makerPosition).toUint256() / totalPosition;
            pnlToBeRealized = _getPnlToBeRealized(takerPosition, makerNotional, reducedOpenNotional);
        } else { // taker position side changes
            // @todo handle case when totalPosition = 0
            uint closedPositionNotional = newNotional * abs(takerPosition).toUint256() / totalPosition;
            pnlToBeRealized = _getPnlToBeRealized(takerPosition, closedPositionNotional, takerOpenNotional);
        }
    }

    function _getPnlToBeRealized(int256 takerPosition, uint notionalPosition, uint openNotional) internal pure returns (int256 pnlToBeRealized) {
        if (takerPosition > 0) {
            pnlToBeRealized = notionalPosition.toInt256() - openNotional.toInt256();
        } else {
            pnlToBeRealized = openNotional.toInt256() - notionalPosition.toInt256();
        }
    }

    function _increasePosition(address trader, int256 baseAssetQuantity, uint quoteAssetLimit)
        internal
        returns(uint quoteAsset)
    {
        if (baseAssetQuantity > 0) { // Long - purchase baseAssetQuantity
            longOpenInterestNotional += baseAssetQuantity.toUint256();
            quoteAsset = _long(baseAssetQuantity, quoteAssetLimit, false /* isLiquidation */);
        } else { // Short - sell baseAssetQuantity
            shortOpenInterestNotional += (-baseAssetQuantity).toUint256();
            quoteAsset = _short(baseAssetQuantity, quoteAssetLimit, false /* isLiquidation */);
        }
        positions[trader].size += baseAssetQuantity; // -ve baseAssetQuantity will increase short position
        positions[trader].openNotional += quoteAsset;
    }

    function _openReversePosition(address trader, int256 baseAssetQuantity, uint quoteAssetLimit)
        internal
        returns (int realizedPnl, uint quoteAsset, bool isPositionIncreased)
    {
        Position memory position = positions[trader];
        if (abs(position.size) >= abs(baseAssetQuantity)) {
            (realizedPnl, quoteAsset) = _reducePosition(trader, baseAssetQuantity, quoteAssetLimit, false /* isLiqudation */);
        } else {
            uint closedRatio = (quoteAssetLimit * abs(position.size).toUint256()) / abs(baseAssetQuantity).toUint256();
            (realizedPnl, quoteAsset) = _reducePosition(trader, -position.size, closedRatio, false /* isLiqudation */);

            // this is required because the user might pass a very less value (slippage-prone) while shorting
            if (quoteAssetLimit >= quoteAsset) {
                quoteAssetLimit -= quoteAsset;
            }
            quoteAsset += _increasePosition(trader, baseAssetQuantity + position.size, quoteAssetLimit);
            isPositionIncreased = true;
        }
    }

    /**
    * @dev validate that baseAssetQuantity <= position.size should be performed before the call to _reducePosition
    */
    function _reducePosition(address trader, int256 baseAssetQuantity, uint quoteAssetLimit, bool isLiquidation)
        internal
        returns (int realizedPnl, uint256 quoteAsset)
    {
        (, int256 unrealizedPnl) = getTakerNotionalPositionAndUnrealizedPnl(trader);

        Position storage position = positions[trader]; // storage because there are updates at the end
        bool isLongPosition = position.size > 0 ? true : false;

        if (isLongPosition) {
            longOpenInterestNotional -= (-baseAssetQuantity).toUint256();
            quoteAsset = _short(baseAssetQuantity, quoteAssetLimit, isLiquidation);
        } else {
            shortOpenInterestNotional -= baseAssetQuantity.toUint256();
            quoteAsset = _long(baseAssetQuantity, quoteAssetLimit, isLiquidation);
        }
        uint256 notionalPosition = getCloseQuote(position.size + baseAssetQuantity);
        (position.openNotional, realizedPnl) = getOpenNotionalWhileReducingPosition(position.size, notionalPosition, unrealizedPnl, baseAssetQuantity);
        position.size += baseAssetQuantity;
    }

    function _addReserveSnapshot(uint256 price, bool isLiquidation)
        internal
    {
        uint256 currentBlock = block.number;
        uint256 blockTimestamp = _blockTimestamp();

        if (reserveSnapshots.length == 0) {
            reserveSnapshots.push(
                ReserveSnapshot(price, blockTimestamp, currentBlock, isLiquidation)
            );
            return;
        }

        ReserveSnapshot storage latestSnapshot = reserveSnapshots[reserveSnapshots.length - 1];
        // update values in snapshot if in the same block
        if (currentBlock == latestSnapshot.blockNumber) {
            latestSnapshot.lastPrice = price;
        } else {
            reserveSnapshots.push(
                ReserveSnapshot(price, blockTimestamp, currentBlock, isLiquidation)
            );
        }
    }

    function _blockTimestamp() internal view virtual returns (uint256) {
        return block.timestamp;
    }

    function _calcTwap(uint256 _intervalInSeconds)
        internal
        view
        returns (uint256)
    {
        uint256 snapshotIndex = reserveSnapshots.length - 1;
        uint256 currentPrice = reserveSnapshots[snapshotIndex].lastPrice;
        if (_intervalInSeconds == 0) {
            return currentPrice;
        }

        uint256 baseTimestamp = _blockTimestamp() - _intervalInSeconds;
        ReserveSnapshot memory currentSnapshot = reserveSnapshots[snapshotIndex];
        // return the latest snapshot price directly
        // if only one snapshot or the timestamp of latest snapshot is earlier than asking for
        if (reserveSnapshots.length == 1 || currentSnapshot.timestamp <= baseTimestamp) {
            return currentPrice;
        }

        uint256 previousTimestamp = currentSnapshot.timestamp;
        uint256 period = _blockTimestamp() - previousTimestamp;
        uint256 weightedPrice = currentPrice * period;
        while (true) {
            // if snapshot history is too short
            if (snapshotIndex == 0) {
                return weightedPrice / period;
            }

            snapshotIndex = snapshotIndex - 1;
            currentSnapshot = reserveSnapshots[snapshotIndex];
            currentPrice = reserveSnapshots[snapshotIndex].lastPrice;

            // check if current round timestamp is earlier than target timestamp
            if (currentSnapshot.timestamp <= baseTimestamp) {
                // weighted time period will be (target timestamp - previous timestamp). For example,
                // now is 1000, _interval is 100, then target timestamp is 900. If timestamp of current round is 970,
                // and timestamp of NEXT round is 880, then the weighted time period will be (970 - 900) = 70,
                // instead of (970 - 880)
                weightedPrice = weightedPrice + (currentPrice * (previousTimestamp - baseTimestamp));
                break;
            }

            uint256 timeFraction = previousTimestamp - currentSnapshot.timestamp;
            weightedPrice = weightedPrice + (currentPrice * timeFraction);
            period = period + timeFraction;
            previousTimestamp = currentSnapshot.timestamp;
        }
        return weightedPrice / _intervalInSeconds;
    }

    function _emitFundingRateUpdated(
        int256 _premiumFraction,
        int256 _underlyingPrice
    ) internal {
        emit FundingRateUpdated(
            _premiumFraction,
            _underlyingPrice.toUint256(),
            cumulativePremiumFraction,
            cumulativePremiumPerDtoken,
            posAccumulator,
            nextFundingTime,
            _blockTimestamp(),
            block.number
        );
    }

    // Pure

    function abs(int x) internal pure returns (int) {
        return x >= 0 ? x : -x;
    }

    function _max(int x, int y) private pure returns (int) {
        return x >= y ? x : y;
    }

    // Governance

    function putAmmInIgnition() external onlyClearingHouse {
        ammState = AMMState.Ignition;
    }

    function changeOracle(address _oracle) public onlyGovernance {
        oracle = IOracle(_oracle);
    }

    function setFundingBufferPeriod(uint _fundingBufferPeriod) external onlyGovernance {
        fundingBufferPeriod = _fundingBufferPeriod;
    }

    function setUnbondPeriod(uint _unbondPeriod) external onlyGovernance {
        unbondPeriod = _unbondPeriod;
    }

    function setMaxOracleSpreadRatio(uint _maxOracleSpreadRatio) external onlyGovernance {
        maxOracleSpreadRatio = _maxOracleSpreadRatio;
    }

    function setLiquidationParams (uint _maxLiquidationRatio, uint _maxLiquidationPriceSpread) external onlyGovernance {
        maxLiquidationRatio = _maxLiquidationRatio;
        maxLiquidationPriceSpread = _maxLiquidationPriceSpread;
    }

    function setMinSizeRequirement(uint _minSizeRequirement) external onlyGovernance {
        minSizeRequirement = _minSizeRequirement;
    }
}

File 2 of 8 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 3 of 8 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

File 4 of 8 : Governable.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";

contract VanillaGovernable {
    address public governance;

    modifier onlyGovernance() {
        require(msg.sender == governance, "ONLY_GOVERNANCE");
        _;
    }

    function setGovernace(address _governance) external onlyGovernance {
        _setGovernace(_governance);
    }

    function _setGovernace(address _governance) internal {
        governance = _governance;
    }
}

contract Governable is VanillaGovernable, Initializable {}

File 5 of 8 : Interfaces.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IRegistry {
    function oracle() external view returns(address);
    function clearingHouse() external view returns(address);
    function vusd() external view returns(address);
    function insuranceFund() external view returns(address);
    function marginAccount() external view returns(address);
}

interface IOracle {
    function getUnderlyingPrice(address asset) external view returns(int256);
    function getUnderlyingTwapPrice(address asset, uint256 intervalInSeconds) external view returns (int256);
}

interface IClearingHouse {
    enum Mode { Maintenance_Margin, Min_Allowable_Margin }
    function openPosition(uint idx, int256 baseAssetQuantity, uint quoteAssetLimit) external;
    function closePosition(uint idx, uint quoteAssetLimit) external;
    function addLiquidity(uint idx, uint256 baseAssetQuantity, uint minDToken) external returns (uint dToken);
    function removeLiquidity(uint idx, uint256 dToken, uint minQuoteValue, uint minBaseValue) external;
    function settleFunding() external;
    function getTotalNotionalPositionAndUnrealizedPnl(address trader, int256 margin, Mode mode)
        external
        view
        returns(uint256 notionalPosition, int256 unrealizedPnl);
    function isAboveMaintenanceMargin(address trader) external view returns(bool);
    function assertMarginRequirement(address trader) external view;
    function updatePositions(address trader) external;
    function getMarginFraction(address trader) external view returns(int256);
    function getTotalFunding(address trader) external view returns(int256 totalFunding);
    function getAmmsLength() external view returns(uint);
    function amms(uint idx) external view returns(IAMM);
    function maintenanceMargin() external view returns(int256);
    function minAllowableMargin() external view returns(int256);
    function tradeFee() external view returns(uint256);
    function liquidationPenalty() external view returns(uint256);
    function getNotionalPositionAndMargin(address trader, bool includeFundingPayments, Mode mode)
        external
        view
        returns(uint256 notionalPosition, int256 margin);
    function isMaker(address trader) external view returns(bool);
    function liquidate(address trader) external;
    function liquidateMaker(address trader) external;
    function liquidateTaker(address trader) external;
    function commitLiquidity(uint idx, uint quoteAsset) external;
    function insuranceFund() external view returns(IInsuranceFund);
    function calcMarginFraction(address trader, bool includeFundingPayments, Mode mode) external view returns(int256);
}

interface ERC20Detailed {
    function decimals() external view returns (uint8);
}

interface IInsuranceFund {
    function seizeBadDebt(uint amount) external;
    function startAuction(address token) external;
    function calcVusdAmountForAuction(address token, uint amount) external view returns(uint);
    function buyCollateralFromAuction(address token, uint amount) external;
}

interface IAMM {
    struct Maker {
        uint vUSD;
        uint vAsset;
        uint dToken;
        int pos; // position
        int posAccumulator; // value of global.posAccumulator until which pos has been updated
        int lastPremiumFraction;
        int lastPremiumPerDtoken;
        uint unbondTime;
        uint unbondAmount;
        uint ignition;
    }

    struct Ignition {
        uint quoteAsset;
        uint baseAsset;
        uint dToken;
    }

    /**
    * @dev We do not deliberately have a Pause state. There is only a master-level pause at clearingHouse level
    */
    enum AMMState { Inactive, Ignition, Active }
    function ammState() external view returns(AMMState);
    function ignition() external view returns(uint quoteAsset, uint baseAsset, uint dToken);
    function getIgnitionShare(uint vUSD) external view returns (uint vAsset, uint dToken);

    function openPosition(address trader, int256 baseAssetQuantity, uint quoteAssetLimit)
        external
        returns (int realizedPnl, uint quoteAsset, bool isPositionIncreased);
    function addLiquidity(address trader, uint baseAssetQuantity, uint minDToken) external returns (uint dToken);
    function removeLiquidity(address maker, uint amount, uint minQuote, uint minBase) external returns (int /* realizedPnl */, uint /* makerOpenNotional */, int /* makerPosition */);
    function forceRemoveLiquidity(address maker) external returns (int realizedPnl, uint makerOpenNotional, int makerPosition);
    function getNotionalPositionAndUnrealizedPnl(address trader)
        external
        view
        returns(uint256 notionalPosition, int256 unrealizedPnl, int256 size, uint256 openNotional);
    function updatePosition(address trader) external returns(int256 fundingPayment);
    function liquidatePosition(address trader) external returns (int realizedPnl, uint quoteAsset);
    function settleFunding() external;
    function underlyingAsset() external view returns (address);
    function positions(address trader) external view returns (int256,uint256,int256,uint256);
    function getCloseQuote(int256 baseAssetQuantity) external view returns(uint256 quoteAssetQuantity);
    function getTakerNotionalPositionAndUnrealizedPnl(address trader) external view returns(uint takerNotionalPosition, int256 unrealizedPnl);
    function getPendingFundingPayment(address trader)
        external
        view
        returns(
            int256 takerFundingPayment,
            int256 makerFundingPayment,
            int256 latestCumulativePremiumFraction,
            int256 latestPremiumPerDtoken
        );
    function getOpenNotionalWhileReducingPosition(int256 positionSize, uint256 notionalPosition, int256 unrealizedPnl, int256 baseAssetQuantity)
        external
        pure
        returns(uint256 remainOpenNotional, int realizedPnl);
    function makers(address maker) external view returns(Maker memory);
    function vamm() external view returns(IVAMM);
    function commitLiquidity(address maker, uint quoteAsset) external;
    function putAmmInIgnition() external;
    function isOverSpreadLimit() external view returns (bool);
    function getOracleBasedPnl(address trader, int256 margin, IClearingHouse.Mode mode) external view returns (uint, int256);
}

interface IMarginAccount {
    struct Collateral {
        IERC20 token;
        uint weight;
        uint8 decimals;
    }

    enum LiquidationStatus {
        IS_LIQUIDATABLE,
        OPEN_POSITIONS,
        NO_DEBT,
        ABOVE_THRESHOLD
    }

    function addMargin(uint idx, uint amount) external;
    function addMarginFor(uint idx, uint amount, address to) external;
    function removeMargin(uint idx, uint256 amount) external;
    function getSpotCollateralValue(address trader) external view returns(int256 spot);
    function weightedAndSpotCollateral(address trader) external view returns(int256, int256);
    function getNormalizedMargin(address trader) external view returns(int256);
    function realizePnL(address trader, int256 realizedPnl) external;
    function isLiquidatable(address trader, bool includeFunding) external view returns(LiquidationStatus, uint, uint);
    function supportedAssetsLen() external view returns(uint);
    function supportedAssets() external view returns (Collateral[] memory);
    function margin(uint idx, address trader) external view returns(int256);
    function transferOutVusd(address recipient, uint amount) external;
    function liquidateExactRepay(address trader, uint repay, uint idx, uint minSeizeAmount) external;
}

interface IVAMM {
    function balances(uint256) external view returns (uint256);

    function get_dy(
        uint256 i,
        uint256 j,
        uint256 dx
    ) external view returns (uint256);

    function get_dx(
        uint256 i,
        uint256 j,
        uint256 dy
    ) external view returns (uint256);

    function exchange(
        uint256 i,
        uint256 j,
        uint256 dx,
        uint256 min_dy
    ) external returns (uint256 dy, uint256 last_price);

    function exchangeExactOut(
        uint256 i,
        uint256 j,
        uint256 dy,
        uint256 max_dx
    ) external returns (uint256 dx, uint256 last_price);

    function get_notional(uint256 makerDToken, uint256 vUSD, uint256 vAsset, int256 takerPosSize, uint256 takerOpenNotional) external view returns (uint256, int256, int256, uint256);
    function last_prices() external view returns(uint256);
    function mark_price() external view returns(uint256);
    function price_oracle() external view returns(uint256);
    function price_scale() external view returns(uint256);
    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external returns (uint256);
    function calc_token_amount(uint256[2] calldata amounts, bool deposit) external view returns (uint256);
    function remove_liquidity(
        uint256 amount,
        uint256[2] calldata minAmounts,
        uint256 vUSD,
        uint256 vAsset,
        uint256 makerDToken,
        int256 takerPosSize,
        uint256 takerOpenNotional
    ) external returns (int256, uint256, uint256, int256, uint[2] calldata);
    function get_maker_position(uint256 amount, uint256 vUSD, uint256 vAsset, uint256 makerDToken) external view returns (int256, uint256, int256);
    function totalSupply() external view returns (uint256);
    function setinitialPrice(uint) external;
}

interface AggregatorV3Interface {

    function decimals() external view returns (uint8);
    function description() external view returns (string memory);
    function version() external view returns (uint256);

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    function getRoundData(uint80 _roundId)
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}

interface IERC20FlexibleSupply is IERC20 {
    function mint(address to, uint256 amount) external;
    function burn(uint256 amount) external;
}

interface IVUSD is IERC20 {
     function mintWithReserve(address to, uint amount) external;
}

interface IUSDC is IERC20FlexibleSupply {
    function masterMinter() external view returns(address);
    function configureMinter(address minter, uint256 minterAllowedAmount) external;
}

interface IHubbleViewer {
    function getMakerPositionAndUnrealizedPnl(address _maker, uint idx)
        external
        view
        returns (int256 position, uint openNotional, int256 unrealizedPnl);
    function clearingHouse() external returns(IClearingHouse);
    function marginAccount() external returns(IMarginAccount);
}

interface IHubbleReferral {
    function getTraderRefereeInfo(address trader) external view returns (address referrer);
}

interface IJoeRouter02 {
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);
    function factory() external returns(address);
    function getAmountsIn(uint256 amountOut, address[] calldata path) external returns (uint256[] memory amounts);
    function getAmountsOut(uint256 amountOut, address[] calldata path) external returns (uint256[] memory amounts);
}

interface IJoePair {
    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;
}

interface IJoeFactory {
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IWAVAX is IERC20 {
    function deposit() external payable;
    function withdraw(uint256) external;
}

File 6 of 8 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.0;

import "../../utils/Address.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
        // contract may have been reentered.
        require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} modifier, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    function _isConstructor() private view returns (bool) {
        return !Address.isContract(address(this));
    }
}

File 7 of 8 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @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
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 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");

        (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");

        (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");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 8 of 8 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_clearingHouse","type":"address"},{"internalType":"uint256","name":"_unbondRoundOff","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"takerFundingPayment","type":"int256"},{"indexed":false,"internalType":"int256","name":"makerFundingPayment","type":"int256"}],"name":"FundingPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"premiumFraction","type":"int256"},{"indexed":false,"internalType":"uint256","name":"underlyingPrice","type":"uint256"},{"indexed":false,"internalType":"int256","name":"cumulativePremiumFraction","type":"int256"},{"indexed":false,"internalType":"int256","name":"cumulativePremiumPerDtoken","type":"int256"},{"indexed":false,"internalType":"int256","name":"posAccumulator","type":"int256"},{"indexed":false,"internalType":"uint256","name":"nextFundingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"FundingRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"dToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseAsset","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteAsset","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"dToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseAsset","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteAsset","type":"uint256"},{"indexed":false,"internalType":"int256","name":"realizedPnl","type":"int256"},{"indexed":false,"internalType":"bool","name":"isLiquidation","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"components":[{"internalType":"uint256","name":"vUSD","type":"uint256"},{"internalType":"uint256","name":"vAsset","type":"uint256"},{"internalType":"uint256","name":"dToken","type":"uint256"},{"internalType":"int256","name":"pos","type":"int256"},{"internalType":"int256","name":"posAccumulator","type":"int256"},{"internalType":"int256","name":"lastPremiumFraction","type":"int256"},{"internalType":"int256","name":"lastPremiumPerDtoken","type":"int256"},{"internalType":"uint256","name":"unbondTime","type":"uint256"},{"internalType":"uint256","name":"unbondAmount","type":"uint256"},{"internalType":"uint256","name":"ignition","type":"uint256"}],"indexed":false,"internalType":"struct IAMM.Maker","name":"maker","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MakerPositionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"size","type":"int256"},{"indexed":false,"internalType":"uint256","name":"openNotional","type":"uint256"},{"indexed":false,"internalType":"int256","name":"realizedPnl","type":"int256"}],"name":"PositionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lastPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"openInterestNotional","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"unbondAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unbondTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Unbonded","type":"event"},{"inputs":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint256","name":"baseAssetQuantity","type":"uint256"},{"internalType":"uint256","name":"minDToken","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"dToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ammState","outputs":[{"internalType":"enum IAMM.AMMState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"changeOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clearingHouse","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint256","name":"quoteAsset","type":"uint256"}],"name":"commitLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cumulativePremiumFraction","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativePremiumPerDtoken","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"}],"name":"forceRemoveLiquidity","outputs":[{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"uint256","name":"makerOpenNotional","type":"uint256"},{"internalType":"int256","name":"makerPosition","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundingBufferPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"baseAssetQuantity","type":"int256"}],"name":"getCloseQuote","outputs":[{"internalType":"uint256","name":"quoteAssetQuantity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vUSD","type":"uint256"}],"name":"getIgnitionShare","outputs":[{"internalType":"uint256","name":"vAsset","type":"uint256"},{"internalType":"uint256","name":"dToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getNotionalPositionAndUnrealizedPnl","outputs":[{"internalType":"uint256","name":"notionalPosition","type":"uint256"},{"internalType":"int256","name":"unrealizedPnl","type":"int256"},{"internalType":"int256","name":"size","type":"int256"},{"internalType":"uint256","name":"openNotional","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"positionSize","type":"int256"},{"internalType":"uint256","name":"newNotionalPosition","type":"uint256"},{"internalType":"int256","name":"unrealizedPnl","type":"int256"},{"internalType":"int256","name":"baseAssetQuantity","type":"int256"}],"name":"getOpenNotionalWhileReducingPosition","outputs":[{"internalType":"uint256","name":"remainOpenNotional","type":"uint256"},{"internalType":"int256","name":"realizedPnl","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"int256","name":"margin","type":"int256"},{"internalType":"enum IClearingHouse.Mode","name":"mode","type":"uint8"}],"name":"getOracleBasedPnl","outputs":[{"internalType":"uint256","name":"notionalPosition","type":"uint256"},{"internalType":"int256","name":"unrealizedPnl","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getPendingFundingPayment","outputs":[{"internalType":"int256","name":"takerFundingPayment","type":"int256"},{"internalType":"int256","name":"makerFundingPayment","type":"int256"},{"internalType":"int256","name":"latestCumulativePremiumFraction","type":"int256"},{"internalType":"int256","name":"latestPremiumPerDtoken","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSnapshotLen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getTakerNotionalPositionAndUnrealizedPnl","outputs":[{"internalType":"uint256","name":"takerNotionalPosition","type":"uint256"},{"internalType":"int256","name":"unrealizedPnl","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_intervalInSeconds","type":"uint256"}],"name":"getTwapPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_intervalInSeconds","type":"uint256"}],"name":"getUnderlyingTwapPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ignition","outputs":[{"internalType":"uint256","name":"quoteAsset","type":"uint256"},{"internalType":"uint256","name":"baseAsset","type":"uint256"},{"internalType":"uint256","name":"dToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"uint256","name":"_minSizeRequirement","type":"uint256"},{"internalType":"address","name":"_vamm","type":"address"},{"internalType":"address","name":"_governance","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOverSpreadLimit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liftOff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"liquidatePosition","outputs":[{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"uint256","name":"quoteAsset","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"longOpenInterestNotional","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"}],"name":"makers","outputs":[{"components":[{"internalType":"uint256","name":"vUSD","type":"uint256"},{"internalType":"uint256","name":"vAsset","type":"uint256"},{"internalType":"uint256","name":"dToken","type":"uint256"},{"internalType":"int256","name":"pos","type":"int256"},{"internalType":"int256","name":"posAccumulator","type":"int256"},{"internalType":"int256","name":"lastPremiumFraction","type":"int256"},{"internalType":"int256","name":"lastPremiumPerDtoken","type":"int256"},{"internalType":"uint256","name":"unbondTime","type":"uint256"},{"internalType":"uint256","name":"unbondAmount","type":"uint256"},{"internalType":"uint256","name":"ignition","type":"uint256"}],"internalType":"struct IAMM.Maker","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidationPriceSpread","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidationRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxOracleSpreadRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minSizeRequirement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextFundingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openInterestNotional","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"int256","name":"baseAssetQuantity","type":"int256"},{"internalType":"uint256","name":"quoteAssetLimit","type":"uint256"}],"name":"openPosition","outputs":[{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"uint256","name":"quoteAsset","type":"uint256"},{"internalType":"bool","name":"isPositionIncreased","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"posAccumulator","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"positions","outputs":[{"internalType":"int256","name":"size","type":"int256"},{"internalType":"uint256","name":"openNotional","type":"uint256"},{"internalType":"int256","name":"lastPremiumFraction","type":"int256"},{"internalType":"uint256","name":"liquidationThreshold","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"putAmmInIgnition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minQuote","type":"uint256"},{"internalType":"uint256","name":"minBase","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"uint256","name":"makerOpenNotional","type":"uint256"},{"internalType":"int256","name":"makerPosition","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"reserveSnapshots","outputs":[{"internalType":"uint256","name":"lastPrice","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bool","name":"isLiquidation","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fundingBufferPeriod","type":"uint256"}],"name":"setFundingBufferPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_governance","type":"address"}],"name":"setGovernace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLiquidationRatio","type":"uint256"},{"internalType":"uint256","name":"_maxLiquidationPriceSpread","type":"uint256"}],"name":"setLiquidationParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxOracleSpreadRatio","type":"uint256"}],"name":"setMaxOracleSpreadRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minSizeRequirement","type":"uint256"}],"name":"setMinSizeRequirement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unbondPeriod","type":"uint256"}],"name":"setUnbondPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleFunding","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shortOpenInterestNotional","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spotPriceTwapInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dToken","type":"uint256"}],"name":"unbondLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unbondPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unbondRoundOff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"updatePosition","outputs":[{"internalType":"int256","name":"fundingPayment","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vamm","outputs":[{"internalType":"contract IVAMM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b50604051620057a4380380620057a483398101604081905262000034916200004b565b6001600160a01b0390911660805260a05262000087565b600080604083850312156200005f57600080fd5b82516001600160a01b03811681146200007757600080fd5b6020939093015192949293505050565b60805160a0516156b1620000f36000396000818161041701526120dd0152600081816104530152818161097f01528181610bd0015281816110e7015281816118050152818161197d015281816124cc01528181612c400152818161317f015261330601526156b16000f3fe608060405234801561001057600080fd5b50600436106103995760003560e01c806362307f44116101e9578063b0200bf41161010f578063e098372c116100ad578063f5a1854a1161007c578063f5a1854a1461086b578063f5c122d41461087e578063f68cd81014610887578063fc0c5ff1146108a157600080fd5b8063e098372c1461082a578063e0beac771461083d578063ed83d79c14610850578063f1b5df861461085857600080fd5b8063bb6e6e53116100e9578063bb6e6e53146107fc578063c2de442f14610805578063c6e7275d1461080e578063e0037a6c1461082157600080fd5b8063b0200bf4146107a6578063b72e1b48146107d6578063bab45f62146107e957600080fd5b80638f5ca38a11610187578063975a6c6111610156578063975a6c61146107555780639af16a95146107685780639cc7fcb61461077b5780639e0103621461078e57600080fd5b80638f5ca38a14610715578063905bb7721461072857806393531f131461073057806393ca2f8a1461074257600080fd5b806374d7c62b116101c357806374d7c62b146106a45780637dc0d1d0146106dc578063851e3ca5146106ef5780638f58f48b1461070257600080fd5b806362307f44146106ad5780637158da7c146106b65780637498a0f0146106c957600080fd5b80632300c1ff116102ce57806345d089131161026c57806355f575101161023b57806355f575101461062e57806355fa3245146106635780635aa6e675146106915780635f1ba1fd146106a457600080fd5b806345d08913146105ec57806347c421b5146105f557806355776b771461060857806355edfbfe1461061b57600080fd5b8063362aecb1116102a8578063362aecb11461054557806337292b60146105d15780633d385e4f146105da5780633fb7b029146105e357600080fd5b80632300c1ff146105175780632565382b1461052a578063349532491461053257600080fd5b80630af968001161033b5780631409136011610315578063140913601461049e57806316f086b7146104a6578063210fdd87146104d957806321e00985146104e257600080fd5b80630af968001461044e5780630d451c8f1461048d57806312eb4f9a1461049557600080fd5b80630413f2b6116103775780630413f2b6146103e2578063053f14da1461040a5780630574f8991461041257806306fdde031461043957600080fd5b806301e3e75d1461039e578063029acde0146103b3578063030a60e6146103cf575b600080fd5b6103b16103ac366004614d61565b6108aa565b005b6103bc600b5481565b6040519081526020015b60405180910390f35b6103b16103dd366004614d91565b61090e565b6103f56103f0366004614d61565b610a54565b604080519283526020830191909152016103c6565b6103bc610a9a565b6103bc7f000000000000000000000000000000000000000000000000000000000000000081565b610441610b37565b6040516103c69190614dbb565b6104757f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103c6565b6013546103bc565b6103bc60115481565b6103b1610bc5565b6104b96104b4366004614e2e565b610c6a565b6040805194855260208501939093529183015260608201526080016103c6565b6103bc60185481565b6104f56104f0366004614d61565b610e0a565b60408051948552602085019390935291830152151560608201526080016103c6565b6103b1610525366004614d61565b610e47565b6103bc610ea6565b6103bc610540366004614d61565b610eb8565b610558610553366004614e2e565b610f63565b6040516103c69190600061014082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525092915050565b6103bc600c5481565b6103bc60075481565b6103bc600a5481565b6103bc600d5481565b6103b1610603366004614e2e565b611046565b6103bc610616366004614e49565b6110da565b6103b1610629366004614efa565b6115fa565b6104b961063c366004614e2e565b600f6020526000908152604090208054600182015460028301546003909301549192909184565b610676610671366004614e2e565b6117f6565b604080519384526020840192909252908201526060016103c6565b600054610475906001600160a01b031681565b6103bc610e1081565b6103bc60095481565b600354610475906001600160a01b031681565b6103f56106d7366004614e2e565b61196f565b600154610475906001600160a01b031681565b6103b16106fd366004614e2e565b611c8b565b6103f5610710366004614ff8565b611d1b565b6103b1610723366004614d61565b611f9f565b6103b1612176565b60145460155460165461067692919083565b61067661075036600461503c565b6124bd565b6103f5610763366004614e2e565b612785565b6103f5610776366004615075565b6129ad565b6103b1610789366004614d61565b612aa4565b610796612b03565b60405190151581526020016103c6565b6107b96107b4366004614e49565b612c31565b6040805193845260208401929092521515908201526060016103c6565b6104b96107e4366004614e2e565b612ec8565b6103b16107f7366004614d61565b6130ae565b6103bc600e5481565b6103bc60055481565b6103b161081c3660046150a7565b61310d565b6103bc60065481565b600254610475906001600160a01b031681565b6103bc61084b366004614e2e565b613172565b6103b16132fb565b6103bc610866366004614d61565b6134aa565b6103bc610879366004614d61565b6134bd565b6103bc60085481565b6017546108949060ff1681565b6040516103c691906150f8565b6103bc60125481565b6000546001600160a01b031633146109095760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e4345000000000000000000000000000000000060448201526064015b60405180910390fd5b601855565b600160175460ff166002811115610927576109276150c9565b146109745760405162461bcd60e51b815260206004820152601060248201527f616d6d5f6e6f745f69676e6974696f6e000000000000000000000000000000006044820152606401610900565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109ec5760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b6109f7600282615197565b6001600160a01b038316600090815260106020526040812060090180549293508392909190610a279084906151ab565b909155505060148054829190600090610a419084906151ab565b90915550610a50905082613560565b5050565b6014546015546000918291610a6a9085906151c3565b610a749190615197565b60145460165491935090610a899085906151c3565b610a939190615197565b9050915091565b600064e8d4a51000600260009054906101000a90046001600160a01b03166001600160a01b031663377d8fbe6040518163ffffffff1660e01b815260040160206040518083038186803b158015610af057600080fd5b505afa158015610b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b289190615200565b610b329190615197565b905090565b60048054610b4490615219565b80601f0160208091040260200160405190810160405280929190818152602001828054610b7090615219565b8015610bbd5780601f10610b9257610100808354040283529160200191610bbd565b820191906000526020600020905b815481529060010190602001808311610ba057829003601f168201915b505050505081565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c3d5760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b601780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000808080600160175460ff166002811115610c8857610c886150c9565b1415610cc7576001600160a01b038516600090815260106020526040902060090154610cb59060026151c3565b60008060009350935093509350610e03565b6001600160a01b03851660009081526010602052604081206009015490808215610cfe57610cf483610a54565b9092509050610d2a565b5050506001600160a01b0385166000908152601060205260409020805460018201546002909201549091905b6002546001600160a01b038981166000908152600f602052604090819020805460019091015491517f5702d1f500000000000000000000000000000000000000000000000000000000815260048101869052602481018890526044810187905260648101919091526084810191909152911690635702d1f59060a40160806040518083038186803b158015610dbe57600080fd5b505afa158015610dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df6919061526d565b9299509750955093505050505b9193509193565b60138181548110610e1a57600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919350919060ff1684565b6000546001600160a01b03163314610ea15760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600555565b6000600b54600a54610b3291906151ab565b6001546003546040517fd6b28b5f0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260248101849052600092919091169063d6b28b5f906044015b60206040518083038186803b158015610f2557600080fd5b505afa158015610f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5d9190615200565b92915050565b610fb9604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b506001600160a01b0316600090815260106020908152604091829020825161014081018452815481526001820154928101929092526002810154928201929092526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e0820152600882015461010082015260099091015461012082015290565b6000546001600160a01b031633146110a05760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111545760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b600260175460ff16600281111561116d5761116d6150c9565b146111ba5760405162461bcd60e51b815260206004820152600e60248201527f616d6d5f6e6f745f6163746976650000000000000000000000000000000000006044820152606401610900565b60185483101561120c5760405162461bcd60e51b815260206004820152600f60248201527f616464696e675f746f6f5f6c65737300000000000000000000000000000000006044820152606401610900565b6002546040517f4903b0d10000000000000000000000000000000000000000000000000000000081526001600482015260009182916001600160a01b0390911690634903b0d19060240160206040518083038186803b15801561126e57600080fd5b505afa158015611282573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a69190615200565b90508061136a57600254604080517fb9e8c9fd00000000000000000000000000000000000000000000000000000000815290516c0c9f2c9cd04674edea40000000926001600160a01b03169163b9e8c9fd916004808301926020929190829003018186803b15801561131757600080fd5b505afa15801561132b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134f9190615200565b61135990876151c3565b6113639190615197565b9150611416565b6002546040517f4903b0d10000000000000000000000000000000000000000000000000000000081526000600482015282916001600160a01b031690634903b0d19060240160206040518083038186803b1580156113c757600080fd5b505afa1580156113db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ff9190615200565b61140990876151c3565b6114139190615197565b91505b6002546040805180820182528481526020810188905290517f0b4c7e4d0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691630b4c7e4d916114719188906004016152cc565b602060405180830381600087803b15801561148b57600080fd5b505af115801561149f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c39190615200565b6001600160a01b03871660009081526010602052604090206002810154919450901561153e57670de0b6b3a76400006114ff826002015461361d565b826004015460095461151191906152e7565b61151b919061535b565b6115259190615417565b816003016000828254611538919061547f565b90915550505b8281600001600082825461155291906151ab565b925050819055508581600101600082825461156d91906151ab565b925050819055508381600201600082825461158891906151ab565b9091555050600954600482015561159e87613560565b6001600160a01b0387167f08d7621a09a86934f387f650007fa17f2413759ca5f2ae0681161b371583a5f58588864260408051948552602085019390935291830152606082015260800160405180910390a25050509392505050565b6000547501000000000000000000000000000000000000000000900460ff166116415760005474010000000000000000000000000000000000000000900460ff1615611645565b303b155b6116b75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610900565b6000547501000000000000000000000000000000000000000000900460ff1615801561171e57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b86516117319060049060208a0190614cd1565b50600380547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0389811691909117909255600180548216888416179055601886905560028054821686841617905560008054909116918416919091179055610384600555620151806011556014600c556203f4806012556019600d55620f4240600e5580156117ed57600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b50505050505050565b60008080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118725760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b6001600160a01b0384166000908152601060205260409020600260175460ff1660028111156118a3576118a36150c9565b141561190d576040805160608101825260008082526020820152600191810191909152600282015460088301546118db9082906136b9565b8360080160008282546118ee91906154f3565b909155506118ff90508782846136d1565b955095509550505050611968565b6001600160a01b038516600090815260106020526040812060090154601480549192909161193c9084906154f3565b90915550506001600160a01b03851660009081526010602052604081206009015561196685613560565b505b9193909250565b600080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119ea5760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b6001600160a01b0383166000908152600f602090815260408083208151608081018352815480825260018301549482019490945260028201549281019290925260030154606082015291908112611a42576000611a45565b60015b90506000611a63611a598460000151613a9e565b84606001516136b9565b601354909150600090611a78906001906154f3565b9050600060138281548110611a8f57611a8f61550a565b90600052602060002090600402016000015490505b4360138381548110611ab857611ab861550a565b906000526020600020906004020160020154148015611ad657508115155b15611b6f5760138281548110611aee57611aee61550a565b600091825260209091206003600490920201015460ff1615611b365760138281548110611b1d57611b1d61550a565b9060005260206000209060040201600001549050611b6f565b611b416001836154f3565b915060138281548110611b5657611b5661550a565b9060005260206000209060040201600001549050611aa4565b6000611b79610a9a565b9050818110611b9357611b8c82826154f3565b9050611ba0565b611b9d81836154f3565b90505b6305f5e100600e5483611bb391906151c3565b611bbd9190615197565b811115611c0c5760405162461bcd60e51b815260206004820152601e60248201527f414d4d2e6c69717569646174696f6e5f70726963655f736c69707061676500006044820152606401610900565b8415611c3b57611c3189611c1f8661361d565b611c2890615539565b60006001613ab6565b9098509650611c76565b611c7089611c488661361d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001613ab6565b90985096505b611c808989613bb9565b505050505050915091565b6000546001600160a01b03163314611ce55760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03831617905550565b6001600160a01b038316600090815260106020908152604080832081516101408101835281548152600180830154948201949094526002820154928101929092526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e0830152600881015461010083015260090154610120820152829160175460ff166002811115611dbc57611dbc6150c9565b1415611ddf57610120810151611dd39060026151c3565b60009250925050611f97565b6001600160a01b038681166000908152600f602090815260408083208151608081018352815480825260018301548286018190526002808501548487015260039094015460608401529254888501518951968a015195517f5702d1f500000000000000000000000000000000000000000000000000000000815260048101919091526024810196909652604486019490945260648501526084840191909152938392911690635702d1f59060a40160806040518083038186803b158015611ea557600080fd5b505afa158015611eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edd919061526d565b92985096509250905085611efb576000809550955050505050611f97565b6000611f068761361d565b611f10878b61547f565b611f1d90620f424061535b565b611f279190615417565b90506000806000611f3a8d8d8789613c45565b9194509250905060008b6001811115611f5557611f556150c9565b1415611f775783811315611f7257611f6c83613e0d565b99508198505b611f8e565b83811215611f8e57611f8883613e0d565b99508198505b50505050505050505b935093915050565b600260175460ff166002811115611fb857611fb86150c9565b146120055760405162461bcd60e51b815260206004820152600e60248201527f616d6d5f6e6f745f6163746976650000000000000000000000000000000000006044820152606401610900565b3361200f81613e5f565b61201881613560565b6001600160a01b03811660009081526010602052604090208261207d5760405162461bcd60e51b815260206004820152600b60248201527f756e626f6e64696e675f300000000000000000000000000000000000000000006044820152606401610900565b82816002015410156120d15760405162461bcd60e51b815260206004820152601260248201527f756e626f6e64696e675f746f6f5f6d75636800000000000000000000000000006044820152606401610900565b600881018390556012547f000000000000000000000000000000000000000000000000000000000000000090819061210990426151ab565b6121139190615197565b61211d91906151c3565b6007820181905560408051858152602081019290925242908201526001600160a01b038316907ffcc4bc9c6b8463463bcbae7de4078e3ef39ab55315563076c4061fc68ad41337906060015b60405180910390a2505050565b6000546001600160a01b031633146121d05760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600160175460ff1660028111156121e9576121e96150c9565b146122365760405162461bcd60e51b815260206004820152601060248201527f616d6d5f6e6f745f69676e6974696f6e000000000000000000000000000000006044820152606401610900565b600061224b612246610384610eb8565b613e0d565b9050600081116122c35760405162461bcd60e51b815260206004820152602360248201527f616d6d2e6c6966744f66662e756e6465726c79696e6750726963655f6e6f745f60448201527f73657400000000000000000000000000000000000000000000000000000000006064820152608401610900565b6002546001600160a01b031663a5debf0e6122e38364e8d4a510006151c3565b6040518263ffffffff1660e01b815260040161230191815260200190565b600060405180830381600087803b15801561231b57600080fd5b505af115801561232f573d6000803e3d6000fd5b5050601454159150612467905057601454819061235490670de0b6b3a76400006151c3565b61235e9190615197565b601581905560025460408051808201825260145481526020810193909352517f0b4c7e4d0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911691630b4c7e4d916123c291906000906004016152cc565b602060405180830381600087803b1580156123dc57600080fd5b505af11580156123f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124149190615200565b6016819055601554601454604080519384526020840192909252828201524260608301525130917f08d7621a09a86934f387f650007fa17f2413759ca5f2ae0681161b371583a5f5919081900360800190a25b601780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166002179055610e1080426124a191906151ab565b6124ab9190615197565b6124b790610e106151c3565b60065550565b60008080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146125395760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b6001600160a01b038716600090815260106020526040902060088101548711156125a55760405162461bcd60e51b815260206004820152601e60248201527f7769746864726177696e675f6d6f72655f7468616e5f756e626f6e64656400006044820152606401610900565b6008810180548890039055600781015442908110156126065760405162461bcd60e51b815260206004820152600f60248201527f7374696c6c5f756e626f6e64696e6700000000000000000000000000000000006044820152606401610900565b601154826007015461261891906151ab565b8111156126675760405162461bcd60e51b815260206004820152601460248201527f77697468647261775f706572696f645f6f7665720000000000000000000000006044820152606401610900565b604080516060810182528881526020810188905260009181019190915261268f8a8a836136d1565b600286015492985090965094501561277857601854836001015410156126f75760405162461bcd60e51b815260206004820152601e60248201527f6c6566746f7665725f6c69717569646974795f69735f746f6f5f6c65737300006044820152606401610900565b6001600160a01b038a166000908152600f602052604081205461271990613a9e565b905080158061272a57506018548110155b6127765760405162461bcd60e51b815260206004820152601d60248201527f72656d6f76696e675f766572795f736d616c6c5f6c69717569646974790000006044820152606401610900565b505b5050509450945094915050565b6001600160a01b0381166000908152600f602090815260408083208151608081018352815480825260018301549482019490945260028201549281019290925260030154606082015282918212156128ba5760025481516001600160a01b039091169063556d6e9f906001906000906127fd90613e0d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526024830191909152604482015260640160206040518083038186803b15801561285957600080fd5b505afa15801561286d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128919190615200565b92506128a0816020015161361d565b6128a98461361d565b6128b391906152e7565b91506129a7565b8051600013156129a75760025481516001600160a01b03909116906337ed3a7a906000906001906128ee9061224690615539565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526024830191909152604482015260640160206040518083038186803b15801561294a57600080fd5b505afa15801561295e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129829190615200565b925061298d8361361d565b61299a826020015161361d565b6129a491906152e7565b91505b50915091565b6000806129b983613a9e565b6129c287613a9e565b1215612a105760405162461bcd60e51b815260206004820152601360248201527f414d4d2e4f4e4c595f5245445543455f504f53000000000000000000000000006044820152606401610900565b6000808713612a20576000612a23565b60015b9050612a2e87613a9e565b612a3785613a9e565b612a41908761535b565b612a4b9190615417565b91506000612a5983876152e7565b90508115612a7f57612a7881612a6e8961361d565b61224691906152e7565b9350612a99565b612a9681612a8c8961361d565b612246919061547f565b93505b505094509492505050565b6000546001600160a01b03163314612afe5760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600c55565b6000600260175460ff166002811115612b1e57612b1e6150c9565b14612b295750600090565b6001546003546040517ffc57d4df0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152600092919091169063fc57d4df9060240160206040518083038186803b158015612b8e57600080fd5b505afa158015612ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc69190615200565b90506000612bd2610a9a565b9050600082821115612bef57612be883836154f3565b9050612bfc565b612bf982846154f3565b90505b82612c088260646151c3565b612c129190615197565b9050600c548110612c27576001935050505090565b6000935050505090565b60008080336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612cad5760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b600260175460ff166002811115612cc657612cc66150c9565b14612d135760405162461bcd60e51b815260206004820152600e60248201527f616d6d5f6e6f745f6163746976650000000000000000000000000000000000006044820152606401610900565b6001600160a01b0386166000908152600f6020908152604080832081516080810183528154808252600183015494820194909452600282015492810192909252600301546060820152919015612d6a576000612d6d565b60015b90506000808813612d7f576001612d82565b60005b90508180612dc35750806001811115612d9d57612d9d6150c9565b8351600012612dad576001612db0565b60005b6001811115612dc157612dc16150c9565b145b15612dde57612dd3898989613ebe565b945060019350612df1565b612de9898989613f92565b919750955093505b6001600160a01b0389166000908152600f6020526040812054612e1390613a9e565b9050801580612e2457506018548110155b612e705760405162461bcd60e51b815260206004820152601a60248201527f706f736974696f6e5f6c6573735f7468616e5f6d696e53697a650000000000006044820152606401610900565b612e956064600d5483612e8391906151c3565b612e8d9190615197565b6018546140a9565b6001600160a01b038b166000908152600f6020526040902060030155612ebb8a88613bb9565b5050505093509350939050565b6001600160a01b0381166000818152600f6020908152604080832081516080808201845282548252600180840154838701526002808501548487019081526003958601546060808701919091529989526010885286892087516101408101895281548152938101549884019890985290870154958201959095529285015496830196909652600484015495820195909552600583015460a0820152600683015460c082015260078084015460e083015260088085015461010084015260099094015461012083015254925485519251949586959193909291670de0b6b3a76400009190612fb590876152e7565b612fbf919061535b565b612fc99190615417565b6001600160a01b03881660009081526010602052604081206009015491975090801561300157612ff881610a54565b92506130099050565b826040015191505b81156130a35760008360a001518761302191906152e7565b9050670de0b6b3a76400006130358461361d565b670de0b6b3a764000083876080015161304e919061535b565b6130589190615417565b60c0870151613067908a6152e7565b61307191906152e7565b61307b919061535b565b82866060015161308b919061535b565b613095919061547f565b61309f9190615417565b9750505b505050509193509193565b6000546001600160a01b031633146131085760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b601255565b6000546001600160a01b031633146131675760405162461bcd60e51b815260206004820152600f60248201527f4f4e4c595f474f5645524e414e434500000000000000000000000000000000006044820152606401610900565b600d91909155600e55565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146131ec5760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b600260175460ff166002811115613205576132056150c9565b1461321257506000919050565b61321b82613e5f565b6001600160a01b0382166000908152601060205260408120908061323e85612ec8565b60068701556005860155909250905061325685613560565b6001600160a01b0385166000908152600f6020526040902060058401546002820155613282828461547f565b945060008512156132a6576132996103e886615417565b6132a390866152e7565b94505b84156132f15760408051848152602081018490526001600160a01b038816917fedccdcc7969b9887e53177a1ae44af75a345795493795e21844486928c385e46910160405180910390a25b505050505b919050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146133735760405162461bcd60e51b815260206004820152601260248201527f4f6e6c7920636c656172696e67486f75736500000000000000000000000000006044820152606401610900565b600260175460ff16600281111561338c5761338c6150c9565b14158061339a575060065442105b156133a157565b60006133ae610e10610eb8565b90506000816133be610e106134aa565b6133c891906152e7565b90506000620151806133dc610e108461535b565b6133e69190615417565b90506000816009546133f8919061535b565b905061340c670de0b6b3a764000082615417565b61341790600161547f565b9050816007600082825461342b919061547f565b925050819055508060086000828254613444919061547f565b909155505060055460009061345990426151ab565b90506000610e108060065461346e91906151ab565b6134789190615197565b61348490610e106151c3565b90508181116134935781613495565b805b6006556134a284876140b9565b505050505050565b6000610f5d6134b883614134565b61361d565b60008082131561352e576002546001600160a01b031663556d6e9f600160006134e586613e0d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935260248301919091526044820152606401610f0d565b6000821215613558576002546001600160a01b03166337ed3a7a600060016134e561224687615539565b506000919050565b6001600160a01b03811660008181526010602052604090207f39e2cd703a0e0eee14b668bc716b6173d6d74486ae0d0cc712a6fd1e5558637690426040516136129291908254815260018301546020820152600283015460408201526003830154606082015260048301546080820152600583015460a0820152600683015460c0820152600783015460e082015260088301546101008201526009909201546101208301526101408201526101600190565b60405180910390a250565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8211156136b55760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e743235360000000000000000000000000000000000000000000000006064820152608401610900565b5090565b60008183106136c857816136ca565b825b9392505050565b60008060008060106000886001600160a01b03166001600160a01b0316815260200190815260200160002090506000600f6000896001600160a01b03166001600160a01b03168152602001908152602001600020905060008060405180604001604052806000815260200160008152509050600260009054906101000a90046001600160a01b03166001600160a01b031663ed4519258a60405180604001604052808c6000015181526020018c6020015181525087600001548860010154896002015489600001548a600101546040518863ffffffff1660e01b81526004016137c09796959493929190615572565b60c060405180830381600087803b1580156137da57600080fd5b505af11580156137ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381291906155b0565b6002890154919b5092995092975093509150600090613832908b906154f3565b905080613856576000600386018190556001860181905580865560028601556138ec565b670de0b6b3a76400006138688261361d565b866004015460095461387a91906152e7565b613884919061535b565b61388e9190615417565b856003015461389d919061547f565b6003860155600285015460018601546138b79083906151c3565b6138c19190615197565b6001860155600285015485546138d89083906151c3565b6138e29190615197565b8555600285018190555b5060095460048501558415613a1857825460009061390a908761535b565b1215613930576139238360000154846001015487614360565b61392d908861547f565b96505b6001830182905582548590849060009061394b90849061547f565b9091555050600d54835461396f9160649161396590613a9e565b612e8391906151c3565b600384015560008513156139a25761398685613e0d565b600a600082825461399791906151ab565b909155506139c59050565b6139ae61224686615539565b600b60008282546139bf91906151ab565b90915550505b7f015fc8ee969fd902d9ebd12a31c54446400a2b512a405366fe14defd6081d2206139ee610a9a565b6139f6610ea6565b6040805192835260208301919091520160405180910390a1613a188a88613bb9565b613a218a613560565b6020810151815160408a01516001600160a01b038d16927f3090ebd533f90973f113db832bb38306dcbd16ea80c1780b9f2121448b329409928d928c90426040805196875260208701959095529385019290925260608401521515608083015260a082015260c00160405180910390a25050505093509350939050565b6000808212156136b557613ab182615539565b610f5d565b6000806000613ac487612785565b6001600160a01b0389166000908152600f6020526040812080549294509250908112613af1576000613af4565b60015b90508015613b3157613b0861224689615539565b600a6000828254613b1991906154f3565b90915550613b2a9050888888614449565b9350613b5f565b613b3a88613e0d565b600b6000828254613b4b91906154f3565b90915550613b5c90508888886147c2565b93505b6000613b74898460000154610879919061547f565b9050613b86836000015482868c6129ad565b6001850191909155835490965089908490600090613ba590849061547f565b925050819055505050505094509492505050565b6001600160a01b0382166000818152600f6020908152604091829020825160808101845281548082526001830154938201849052600283015482860152600390920154606082015292519293927f9ffd1f40a44de66f6b3803ad672fbf4773eca3c1494ef736cb8007e14f9ea1e492612169929187909283526020830191909152604082015260600190565b6001546003546040517ffc57d4df0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152600092839283928392919091169063fc57d4df9060240160206040518083038186803b158015613cb057600080fd5b505afa158015613cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce89190615200565b9050670de0b6b3a7640000613cfc86613a9e565b613d06908361535b565b613d109190615417565b93506000851315613d3557613d248661361d565b613d2e90856152e7565b9250613d55565b6000851215613d555783613d488761361d565b613d5291906152e7565b92505b6001600160a01b0388166000908152600f6020526040812054670de0b6b3a764000090613d8190613a9e565b613d8b908461535b565b613d959190615417565b6001600160a01b038a16600090815260106020526040902054909150613ddb908290613dc09061361d565b613dcb90600261535b565b613dd5919061547f565b86614a19565b945084613de8858a61547f565b613df590620f424061535b565b613dff9190615417565b925050509450945094915050565b6000808212156136b55760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610900565b6001600160a01b03811660009081526010602052604090206009015480613e84575050565b6001600160a01b0382166000908152601060205260409020818155613ea882610a54565b6002830155600182015560006009909101555050565b600080831315613efb57613ed183613e0d565b600a6000828254613ee291906151ab565b90915550613ef49050838360006147c2565b9050613f2d565b613f0761224684615539565b600b6000828254613f1891906151ab565b90915550613f2a905083836000614449565b90505b6001600160a01b0384166000908152600f602052604081208054859290613f5590849061547f565b90915550506001600160a01b0384166000908152600f602052604081206001018054839290613f859084906151ab565b9091555090949350505050565b6001600160a01b0383166000908152600f6020908152604080832081516080810183528154815260018201549381019390935260028101549183019190915260030154606082015281908190613fe786613a9e565b8151613ff290613a9e565b1261400e576140048787876000613ab6565b909450925061409f565b600061401c61224688613a9e565b61402c6122468460000151613a9e565b61403690886151c3565b6140409190615197565b905061405c88836000015161405490615539565b836000613ab6565b90955093508386106140755761407284876154f3565b95505b815161408d908990614087908a61547f565b88613ebe565b61409790856151ab565b935060019250505b5093509350939050565b6000818310156136c857816136ca565b7f63e1c3bbc27ccaa3683a3c85a499d5547c8942bb17dabc9490d3b2cf2ec6a35a826140e483613e0d565b60075460085460095460065442604080519788526020880196909652948601939093526060850191909152608084015260a083015260c08201524360e08201526101000160405180910390a15050565b6013546000908190614148906001906154f3565b905060006013828154811061415f5761415f61550a565b90600052602060002090600402016000015490508360001415614183579392505050565b600061418f85426154f3565b90506000601384815481106141a6576141a661550a565b600091825260209182902060408051608081018252600490930290910180548352600180820154948401949094526002810154918301919091526003015460ff16151560608201526013549092501480614204575081816020015111155b15614213575090949350505050565b6020810151600061422482426154f3565b9050600061423282876151c3565b90505b86614251576142448282615197565b9998505050505050505050565b61425c6001886154f3565b9650601387815481106142715761427161550a565b60009182526020918290206040805160808101825260049093029091018054835260018101549383019390935260028301549082015260039091015460ff16151560608201526013805491955090889081106142cf576142cf61550a565b906000526020600020906004020160000154955084846020015111614313576142f885846154f3565b61430290876151c3565b61430c90826151ab565b9050614356565b600084602001518461432591906154f3565b905061433181886151c3565b61433b90836151ab565b915061434781846151ab565b92508460200151935050614235565b6142448982615197565b600080614370610879848761547f565b90506000614389612246614384888761547f565b613a9e565b905061439484613a9e565b61439d87613a9e565b131561440c5760006143b161224688613a9e565b6143bd61224687613a9e565b6143c790886151c3565b6143d19190615197565b90506000826143e261224688613a9e565b6143ec90866151c3565b6143f69190615197565b9050614403888284614a29565b94505050614440565b60008161441b61224689613a9e565b61442590856151c3565b61442f9190615197565b905061443c878288614a29565b9350505b50509392505050565b60008084126144c05760405162461bcd60e51b815260206004820152602660248201527f56414d4d2e5f73686f72743a206261736541737365745175616e74697479206960448201527f73203e3d203000000000000000000000000000000000000000000000000000006064820152608401610900565b6002546000906001600160a01b0316635b41b9086001836144e36122468a615539565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935260248301919091526044820152606481018790526084016040805180830381600087803b15801561454757600080fd5b505af115801561455b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061457f9190615657565b6001546003546040517ffc57d4df0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015293955091935060009291169063fc57d4df9060240160206040518083038186803b1580156145e857600080fd5b505afa1580156145fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146209190615200565b90506064600c54606461463391906154f3565b61463d90836151c3565b6146479190615197565b90508315801561465657508082105b156146a35760405162461bcd60e51b815260206004820152601f60248201527f56414d4d2e5f73686f72743a2073686f727473206e6f7420616c6c6f776564006044820152606401610900565b6146ad8285614a7a565b600254604080517f18160ddd0000000000000000000000000000000000000000000000000000000081529051614744926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561470c57600080fd5b505afa158015614720573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134b89190615200565b61475687670de0b6b3a764000061535b565b6147609190615417565b6009600082825461477191906152e7565b909155507f015fc8ee969fd902d9ebd12a31c54446400a2b512a405366fe14defd6081d2209050826147a1610ea6565b6040805192835260208301919091520160405180910390a150509392505050565b60008084136148395760405162461bcd60e51b815260206004820152602560248201527f56414d4d2e5f6c6f6e673a206261736541737365745175616e7469747920697360448201527f203c3d20300000000000000000000000000000000000000000000000000000006064820152608401610900565b6002546000906001600160a01b0316635e90cf0e82600161485989613e0d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935260248301919091526044820152606481018790526084016040805180830381600087803b1580156148bd57600080fd5b505af11580156148d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f59190615657565b6001546003546040517ffc57d4df0000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015293955091935060009291169063fc57d4df9060240160206040518083038186803b15801561495e57600080fd5b505afa158015614972573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149969190615200565b90506064600c5460646149a991906151ab565b6149b390836151c3565b6149bd9190615197565b9050831580156149cc57508082115b156146a35760405162461bcd60e51b815260206004820152601d60248201527f56414d4d2e5f6c6f6e673a206c6f6e6773206e6f7420616c6c6f7765640000006044820152606401610900565b6000818312156136c857816136ca565b600080841315614a5657614a3c8261361d565b614a458461361d565b614a4f91906152e7565b90506136ca565b614a5f8361361d565b614a688361361d565b614a7291906152e7565b949350505050565b60135443904290614b835760408051608081018252948552602085019182528401918252911515606084019081526013805460018101825560009190915293517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09060049095029485015591517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a091840155517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a092830155517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6013805460009190614b97906001906154f3565b81548110614ba757614ba761550a565b906000526020600020906004020190508060020154831415614bcb57848155614cca565b6040805160808101825286815260208101848152918101858152861515606083019081526013805460018101825560009190915292517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09060049094029384015592517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a091830155517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09282015590517f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790555b5050505050565b828054614cdd90615219565b90600052602060002090601f016020900481019282614cff5760008555614d45565b82601f10614d1857805160ff1916838001178555614d45565b82800160010185558215614d45579182015b82811115614d45578251825591602001919060010190614d2a565b506136b59291505b808211156136b55760008155600101614d4d565b600060208284031215614d7357600080fd5b5035919050565b80356001600160a01b03811681146132f657600080fd5b60008060408385031215614da457600080fd5b614dad83614d7a565b946020939093013593505050565b600060208083528351808285015260005b81811015614de857858101830151858201604001528201614dcc565b81811115614dfa576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600060208284031215614e4057600080fd5b6136ca82614d7a565b600080600060608486031215614e5e57600080fd5b614e6784614d7a565b95602085013595506040909401359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614ef257614ef2614e7c565b604052919050565b60008060008060008060c08789031215614f1357600080fd5b863567ffffffffffffffff80821115614f2b57600080fd5b818901915089601f830112614f3f57600080fd5b8135602082821115614f5357614f53614e7c565b614f83817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011601614eab565b92508183528b81838601011115614f9957600080fd5b81818501828501376000818385010152829950614fb7818c01614d7a565b985050505050614fc960408801614d7a565b935060608701359250614fde60808801614d7a565b9150614fec60a08801614d7a565b90509295509295509295565b60008060006060848603121561500d57600080fd5b61501684614d7a565b92506020840135915060408401356002811061503157600080fd5b809150509250925092565b6000806000806080858703121561505257600080fd5b61505b85614d7a565b966020860135965060408601359560600135945092505050565b6000806000806080858703121561508b57600080fd5b5050823594602084013594506040840135936060013592509050565b600080604083850312156150ba57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310615133577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000826151a6576151a6615139565b500490565b600082198211156151be576151be615168565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156151fb576151fb615168565b500290565b60006020828403121561521257600080fd5b5051919050565b600181811c9082168061522d57607f821691505b60208210811415615267577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000806000806080858703121561528357600080fd5b505082516020840151604085015160609095015191969095509092509050565b8060005b60028110156152c65781518452602093840193909101906001016152a7565b50505050565b606081016152da82856152a3565b8260408301529392505050565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561532157615321615168565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01831381161561535557615355615168565b50500390565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561539c5761539c615168565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156153d7576153d7615168565b600087129250878205871284841616156153f3576153f3615168565b8785058712818416161561540957615409615168565b505050929093029392505050565b60008261542657615426615139565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561547a5761547a615168565b500590565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038413811516156154b9576154b9615168565b827f80000000000000000000000000000000000000000000000000000000000000000384128116156154ed576154ed615168565b50500190565b60008282101561550557615505615168565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007f800000000000000000000000000000000000000000000000000000000000000082141561556b5761556b615168565b5060000390565b878152610100810161558760208301896152a3565b6060820196909652608081019490945260a084019290925260c083015260e09091015292915050565b600080600080600060c086880312156155c857600080fd5b855194506020808701519450604087015193506060870151925087609f8801126155f157600080fd5b6040516040810181811067ffffffffffffffff8211171561561457615614614e7c565b6040528060c089018a81111561562957600080fd5b60808a015b81811015615645578051835291840191840161562e565b50505080925050509295509295909350565b6000806040838503121561566a57600080fd5b50508051602090910151909290915056fea264697066735822122066f243e3120fedcebae04e5daf98bda0e1253993bf5f88974dac46db9946b74c64736f6c634300080900330000000000000000000000004e3535964cb5612a466d8bb25362d485452efcef0000000000000000000000000000000000000000000000000000000000015180

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000004e3535964cb5612a466d8bb25362d485452efcef0000000000000000000000000000000000000000000000000000000000015180

-----Decoded View---------------
Arg [0] : _clearingHouse (address): 0x4e3535964cb5612a466d8bb25362d485452efcef
Arg [1] : _unbondRoundOff (uint256): 86400

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000004e3535964cb5612a466d8bb25362d485452efcef
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.