Contract 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655

Txn Hash Method
Block
From
To
Value [Txn Fee]
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55Sell USDG117247802021-08-23 8:52:0525 days 14 hrs ago0x56a2a358d687a40e3bfd2be28e69ab229e0b444e IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00143801
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e3042636Liquidate Positi...99576372021-06-22 13:57:3187 days 9 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0014975
0x40355a59d5f573be2211e7a774170ab8ccc65a890153dd6fef8635a36a96d239Liquidate Positi...99575362021-06-22 13:52:2887 days 9 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0003919
0x3a4b100fd878fecbe30460e3197dba277143d83a07d84936d09b9d77d699b8a6Liquidate Positi...99575362021-06-22 13:52:2887 days 9 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00159641
0xe8dfc2721ce281eae142f1c67f3aa402db3148b5f7ebba9769cd0d7256c3c707Liquidate Positi...99573472021-06-22 13:43:0187 days 9 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148841
0x5b4db6a6b5ecde174844223dcbacdbb60d30e2ac5079d58edd5dc64623975f93Liquidate Positi...99573452021-06-22 13:42:5587 days 9 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148841
0x50c9ecf44f79b922f9164779239b5400ddbbef924e5459a911ac6858a977fe20Liquidate Positi...99564232021-06-22 12:56:4987 days 10 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148841
0x96ebf435102d28d8a1b11110d9dec88482944430afe78b192b30002f02883f83Liquidate Positi...99564212021-06-22 12:56:4387 days 10 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0014975
0xc870f61b9dc78b0a3c9e94e13ec891cecf15a884a0eff098329de8405b97816dLiquidate Positi...99562372021-06-22 12:47:3187 days 10 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00171221
0x1ad84cfe34b281b536949f5912af51dd9746050e1459f430f3c6acd026c6702bLiquidate Positi...99554332021-06-22 12:07:1987 days 11 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00172295
0x2d608f864bafcdfd1be75991b9c44659d7f2f654f11c1e57db88115fba94c3f5Liquidate Positi...90981112021-05-23 16:45:42117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0xbf3e99f6cad3403905a6bf875061fffec159f75166506069b5959d39a9a6bd14Liquidate Positi...90981092021-05-23 16:45:36117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00172295
0xc74097fceddd7a35643e508f9a70d434bd3fd3fe98512dfb96b5d18b72af45b3Liquidate Positi...90979692021-05-23 16:38:36117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0014975
0xb5be5d5691f42822f04d49bc00850b19936ffe6f59a0e02beac94ce969a409d6Liquidate Positi...90979682021-05-23 16:38:33117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00160465
0x317d2fbc8b2e2e1a992dc3dde7cc19cb3079083d42883b5694fbd24314a192b4Liquidate Positi...90979662021-05-23 16:38:27117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0014975
0xbba2277c81c68a9652a616c48f62d28d16ba58cfdc0413838d121a6340978157Liquidate Positi...90979642021-05-23 16:38:21117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00138041
0x4aa65974cd975374998225b9653ab3718c7921f8bae6c73afc3c388dc4e998eeLiquidate Positi...90978142021-05-23 16:30:51117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0x24bb02ac83bf9f43f7cc5199e6b510d825f50e8d42822c1d75e16747def5fbedLiquidate Positi...90978122021-05-23 16:30:45117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0xe980e83d95987bc99353a94cea50fe5266bf6e8d85a9cc98fc5bdb70e0d0ce2cLiquidate Positi...90978102021-05-23 16:30:39117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0x4972a398c727dd874a67b0c4581a6d062f6997ba516a98a44382fce08a36f0b3Liquidate Positi...90978082021-05-23 16:30:33117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148841
0xf79672fad0fc066c0d6be4ddfa9f01e6ea12475c43dce8721510ea4d06b49d61Liquidate Positi...90978072021-05-23 16:30:30117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0x8333fdb68f279b8626ff4a115047bb8ba4f629ad9d0c8b1d4c49d7c9d200aa8aLiquidate Positi...90978052021-05-23 16:30:24117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148577
0x24637c7dbd13c816041799fc9ca93b9b782f7db9186c5bb00ec11df05a6fc58aLiquidate Positi...90978032021-05-23 16:30:18117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.0014975
0xf3eb0f8e0404a173dbc018a849095596d43a71ee5677762bda103c2c2ee9b7a4Liquidate Positi...90978012021-05-23 16:30:12117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00148589
0x97a4526233121a15863682956efaee55866e933f5b82470a3bc01e8832b98677Liquidate Positi...90977992021-05-23 16:30:06117 days 6 hrs ago0xe16dbcb955f53940609c96a5f87c6acf41817a74 IN  0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB0.00159641
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xe14f46ee1e23b68003bced6d85465455a309dfff0 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x6a2345e019db2acc6007dcd3a69731f51d7dca520 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x6a2345e019db2acc6007dcd3a69731f51d7dca520 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xe14f46ee1e23b68003bced6d85465455a309dfff0 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xe14f46ee1e23b68003bced6d85465455a309dfff0 BNB
0xfb00dd9231c30e10e983c163c2a7a0e07daac5884b699510fe0bfb7101c9219d117253152021-08-23 9:18:5025 days 14 hrs ago 0xeab009d0e467f6bd9a98cd9e9d3b7da909ae7f48 0x3239bf99d4d1f7ca2ddada64e0345053bfb456550 BNB
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55117247802021-08-23 8:52:0525 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55117247802021-08-23 8:52:0525 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55117247802021-08-23 8:52:0525 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55117247802021-08-23 8:52:0525 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x2514895c72f50d8bd4b4f9b1110f0d6bd2c975260 BNB
0x6335e1ba68521073b0cc2d66fe1c0ee705c9c59c0ba1d32cc2974875e5068c55117247802021-08-23 8:52:0525 days 14 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xe14f46ee1e23b68003bced6d85465455a309dfff0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xd19a92c0f37880cd3d19cbc8bb2636e7051f7d890 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0xd19a92c0f37880cd3d19cbc8bb2636e7051f7d890 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
0x3ceb9f710c2867496468069aee8318af8e7741c54a0b689f23dc2166e304263699576372021-06-22 13:57:3187 days 9 hrs ago 0x3239bf99d4d1f7ca2ddada64e0345053bfb45655 0x5741306c21795fdcbb9b265ea0255f499dfe515c0 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Vault

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 9 : Vault.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

import "../libraries/math/SafeMath.sol";
import "../libraries/token/IERC20.sol";
import "../libraries/token/SafeERC20.sol";
import "../libraries/utils/ReentrancyGuard.sol";

import "../oracle/interfaces/IPriceFeed.sol";

import "../tokens/interfaces/IUSDG.sol";
import "./interfaces/IVault.sol";

contract Vault is ReentrancyGuard, IVault {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

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

    uint256 constant BASIS_POINTS_DIVISOR = 10000;
    uint256 constant FUNDING_RATE_PRECISION = 1000000;
    uint256 constant PRICE_PRECISION = 10 ** 30;
    uint256 constant MIN_LEVERAGE = 10000; // 1x
    uint256 constant USDG_DECIMALS = 18;
    uint256 constant MAX_FEE_BASIS_POINTS = 500; // 5%
    uint256 constant MAX_LIQUIDATION_FEE_USD = 100 * PRICE_PRECISION; // 100 USD
    uint256 constant MIN_FUNDING_RATE_INTERVAL = 1 hours;
    uint256 constant MAX_FUNDING_RATE_FACTOR = 10000; // 1%

    bool public isInitialized;

    address public router;

    address public usdg;
    address public gov;

    uint256 public maxUsdg;
    uint256 public maxLeverage = 50 * 10000; // 50x
    uint256 public priceSampleSpace = 3;

    uint256 public liquidationFeeUsd;
    uint256 public swapFeeBasisPoints = 30; // 0.3%
    uint256 public stableSwapFeeBasisPoints = 4; // 0.04%
    uint256 public marginFeeBasisPoints = 10; // 0.1%

    uint256 public fundingInterval = 8 hours;
    uint256 public override fundingRateFactor;

    mapping (address => mapping (address => bool)) public approvedRouters;

    mapping (address => bool) public whitelistedTokens;
    mapping (address => address) public priceFeeds;
    mapping (address => uint256) public priceDecimals;
    mapping (address => uint256) public tokenDecimals;
    mapping (address => uint256) public redemptionBasisPoints;
    mapping (address => uint256) public minProfitBasisPoints;
    mapping (address => bool) public stableTokens;

    // tokenBalances is used only to determine _transferIn values
    mapping (address => uint256) public tokenBalances;

    // usdgAmounts tracks the amount of USDG debt for each whitelisted token
    mapping (address => uint256) public override usdgAmounts;

    // poolAmounts tracks the number of received tokens that can be used for leverage
    // this is tracked separately from tokenBalances to exclude funds that are deposited as margin collateral
    mapping (address => uint256) public override poolAmounts;

    // reservedAmounts tracks the number of tokens reserved for open leverage positions
    mapping (address => uint256) public override reservedAmounts;

    // guaranteedUsd tracks the amount of USD that is "guaranteed" by opened leverage positions
    // this value is used to calculate the redemption values for selling of USDG
    // this is an estimated amount, it is possible for the actual guaranteed value to be lower
    // in the case of sudden price decreases, the guaranteed value should be corrected
    // after liquidations are carried out
    mapping (address => uint256) public guaranteedUsd;

    mapping (address => uint256) public override cumulativeFundingRates;
    mapping (address => uint256) public lastFundingTimes;

    mapping (bytes32 => Position) public positions;

    mapping (address => uint256) public feeReserves;

    event BuyUSDG(address token, uint256 tokenAmount, uint256 usdgAmount);
    event SellUSDG(address token, uint256 usdgAmount, uint256 tokenAmount);
    event Swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut);

    event IncreasePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        uint256 sizeDelta,
        bool isLong
    );
    event DecreasePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        uint256 collateralDelta,
        uint256 sizeDelta,
        bool isLong
    );
    event LiquidatePosition(
        bytes32 key,
        address account,
        address collateralToken,
        address indexToken,
        bool isLong,
        uint256 size,
        uint256 collateral,
        uint256 reserveAmount
    );
    event UpdatePosition(
        bytes32 key,
        uint256 size,
        uint256 collateral,
        uint256 averagePrice,
        uint256 entryFundingRate,
        uint256 reserveAmount
    );

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

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

    event IncreasePoolAmount(address token, uint256 amount);
    event DecreasePoolAmount(address token, uint256 amount);
    event IncreaseUsdgAmount(address token, uint256 amount);
    event DecreaseUsdgAmount(address token, uint256 amount);
    event IncreaseReservedAmount(address token, uint256 amount);
    event DecreaseReservedAmount(address token, uint256 amount);
    event IncreaseGuaranteedUsd(address token, uint256 amount);
    event DecreaseGuaranteedUsd(address token, uint256 amount);

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

    // once the parameters are verified to be working correctly,
    // gov should be set to a timelock contract or a governance contract
    constructor() public {
        gov = msg.sender;
    }

    function initialize(
        address _router,
        address _usdg,
        uint256 _maxUsdg,
        uint256 _liquidationFeeUsd,
        uint256 _fundingRateFactor
    ) external onlyGov {
        require(!isInitialized, "Vault: already initialized");
        isInitialized = true;

        router = _router;
        usdg = _usdg;
        maxUsdg = _maxUsdg;
        liquidationFeeUsd = _liquidationFeeUsd;
        fundingRateFactor = _fundingRateFactor;
    }

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

    function setMaxUsdg(uint256 _maxUsdg) external nonReentrant onlyGov {
        maxUsdg = _maxUsdg;
    }

    function setMaxLeverage(uint256 _maxLeverage) external nonReentrant onlyGov {
        require(_maxLeverage > MIN_LEVERAGE, "Vault: invalid _maxLeverage");
        maxLeverage = _maxLeverage;
    }

    function setPriceSampleSpace(uint256 _priceSampleSpace) external nonReentrant onlyGov {
        require(_priceSampleSpace > 0, "Vault: invalid _priceSampleSpace");
        priceSampleSpace = _priceSampleSpace;
    }

    function setFees(
        uint256 _swapFeeBasisPoints,
        uint256 _stableSwapFeeBasisPoints,
        uint256 _marginFeeBasisPoints,
        uint256 _liquidationFeeUsd
    ) external nonReentrant onlyGov {
        require(_swapFeeBasisPoints <= MAX_FEE_BASIS_POINTS, "Vault: invalid _swapFeeBasisPoints");
        require(_stableSwapFeeBasisPoints <= MAX_FEE_BASIS_POINTS, "Vault: invalid _stableSwapFeeBasisPoints");
        require(_marginFeeBasisPoints <= MAX_FEE_BASIS_POINTS, "Vault: invalid _marginFeeBasisPoints");
        require(_liquidationFeeUsd <= MAX_LIQUIDATION_FEE_USD, "Vault: invalid _liquidationFeeUsd");
        liquidationFeeUsd = _liquidationFeeUsd;
        swapFeeBasisPoints = _swapFeeBasisPoints;
        stableSwapFeeBasisPoints = _stableSwapFeeBasisPoints;
        marginFeeBasisPoints = _marginFeeBasisPoints;
    }

    function setFundingRate(uint256 _fundingInterval, uint256 _fundingRateFactor) external nonReentrant onlyGov {
        require(_fundingInterval > MIN_FUNDING_RATE_INTERVAL, "Vault: invalid _fundingInterval");
        require(_fundingRateFactor <= MAX_FUNDING_RATE_FACTOR, "Vault: invalid _fundingRateFactor");
        fundingInterval = _fundingInterval;
        fundingRateFactor = _fundingRateFactor;
    }

    function setTokenConfig(
        address _token,
        address _priceFeed,
        uint256 _priceDecimals,
        uint256 _tokenDecimals,
        uint256 _redemptionBps,
        uint256 _minProfitBps,
        bool _isStable
    ) external nonReentrant onlyGov {
        whitelistedTokens[_token] = true;
        priceFeeds[_token] = _priceFeed;
        priceDecimals[_token] = _priceDecimals;
        tokenDecimals[_token] = _tokenDecimals;
        redemptionBasisPoints[_token] = _redemptionBps;
        minProfitBasisPoints[_token] = _minProfitBps;
        stableTokens[_token] = _isStable;

        // validate price feed
        getMaxPrice(_token);
    }

    function clearTokenConfig(address _token) external nonReentrant onlyGov {
        require(whitelistedTokens[_token], "Vault: token not whitelisted");
        delete whitelistedTokens[_token];
        delete priceFeeds[_token];
        delete priceDecimals[_token];
        delete tokenDecimals[_token];
        delete redemptionBasisPoints[_token];
        delete minProfitBasisPoints[_token];
        delete stableTokens[_token];
    }

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

    function addRouter(address _router) external {
        approvedRouters[msg.sender][_router] = true;
    }

    function removeRouter(address _router) external {
        approvedRouters[msg.sender][_router] = false;
    }

    function buyUSDG(address _token, address _receiver) external override nonReentrant returns (uint256) {
        require(whitelistedTokens[_token], "Vault: _token not whitelisted");

        uint256 tokenAmount = _transferIn(_token);
        require(tokenAmount > 0, "Vault: invalid tokenAmount");

        updateCumulativeFundingRate(_token);

        uint256 price = getMinPrice(_token);

        uint256 amountAfterFees = _collectSwapFees(_token, tokenAmount, stableTokens[_token]);
        uint256 usdgAmount = amountAfterFees.mul(price).div(PRICE_PRECISION);
        usdgAmount = adjustForDecimals(usdgAmount, _token, usdg);
        require(usdgAmount > 0, "Vault: invalid usdgAmount");
        require(IERC20(usdg).totalSupply().add(usdgAmount) <= maxUsdg, "Vault: maxUsdg exceeded");

        IUSDG(usdg).mint(_receiver, usdgAmount);

        _increaseUsdgAmount(_token, usdgAmount);
        _increasePoolAmount(_token, amountAfterFees);

        emit BuyUSDG(_token, tokenAmount, usdgAmount);

        return usdgAmount;
    }

    function sellUSDG(address _token, address _receiver) external override nonReentrant returns (uint256) {
        require(whitelistedTokens[_token], "Vault: _token not whitelisted");

        uint256 usdgAmount = _transferIn(usdg);
        require(usdgAmount > 0, "Vault: invalid usdgAmount");

        updateCumulativeFundingRate(_token);

        uint256 redemptionAmount = getRedemptionAmount(_token, usdgAmount);
        require(redemptionAmount > 0, "Vault: invalid redemptionAmount");

        _decreaseUsdgAmount(_token, usdgAmount);
        _decreasePoolAmount(_token, redemptionAmount);

        IUSDG(usdg).burn(address(this), usdgAmount);

        uint256 tokenAmount = _collectSwapFees(_token, redemptionAmount, stableTokens[_token]);
        require(tokenAmount > 0, "Vault: invalid tokenAmount");
        _transferOut(_token, tokenAmount, _receiver);

        // the _transferIn call increased the value of tokenBalances[usdg]
        // usually decreases in token balances are synced by calling _transferOut
        // however, for usdg, the tokens are burnt, so _updateTokenBalance should
        // be manually called to record the decrease in tokens
        _updateTokenBalance(usdg);

        emit SellUSDG(_token, usdgAmount, tokenAmount);

        return tokenAmount;
    }

    function swap(address _tokenIn, address _tokenOut, address _receiver) external override nonReentrant returns (uint256) {
        require(whitelistedTokens[_tokenIn], "Vault: _tokenIn not whitelisted");
        require(whitelistedTokens[_tokenOut], "Vault: _tokenOut not whitelisted");
        updateCumulativeFundingRate(_tokenIn);
        updateCumulativeFundingRate(_tokenOut);

        uint256 amountIn = _transferIn(_tokenIn);
        require(amountIn > 0, "Vault: invalid amountIn");

        uint256 priceIn = getMinPrice(_tokenIn);
        uint256 priceOut = getMaxPrice(_tokenOut);

        uint256 amountOut = amountIn.mul(priceIn).div(priceOut);
        amountOut = adjustForDecimals(amountOut, _tokenIn, _tokenOut);
        uint256 amountAfterFees = _collectSwapFees(_tokenOut, amountOut, stableTokens[_tokenIn] && stableTokens[_tokenOut]);

        // adjust usdgAmounts by the same usdAmount as debt is shifted between the assets
        uint256 usdAmount = amountIn.mul(priceIn).div(PRICE_PRECISION);
        uint256 usdIn = adjustForDecimals(usdAmount, _tokenIn, usdg);
        uint256 usdOut = adjustForDecimals(usdAmount, _tokenOut, usdg);

        _increaseUsdgAmount(_tokenIn, usdIn);
        _decreaseUsdgAmount(_tokenOut, usdOut);

        _increasePoolAmount(_tokenIn, amountIn);
        _decreasePoolAmount(_tokenOut, amountOut);

        _transferOut(_tokenOut, amountAfterFees, _receiver);

        emit Swap(_tokenIn, _tokenOut, amountIn, amountAfterFees);

        return amountAfterFees;
    }

    function increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external override nonReentrant {
        _validateRouter(_account);
        _validateTokens(_collateralToken, _indexToken, _isLong);
        updateCumulativeFundingRate(_collateralToken);

        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position storage position = positions[key];

        uint256 price = _isLong ? getMaxPrice(_indexToken) : getMinPrice(_indexToken);

        if (position.size == 0) {
            position.averagePrice = price;
        }

        if (position.size > 0 && _sizeDelta > 0) {
            position.averagePrice = getNextAveragePrice(_indexToken, position.size, position.averagePrice, _isLong, price, _sizeDelta);
        }

        uint256 fee = _collectMarginFees(_collateralToken, _sizeDelta, position.size, position.entryFundingRate);
        uint256 collateralDelta = _transferIn(_collateralToken);
        uint256 collateralDeltaUsd = tokenToUsdMin(_collateralToken, collateralDelta);

        position.collateral = position.collateral.add(collateralDeltaUsd);
        require(position.collateral >= fee, "Vault: insufficient collateral for fees");

        position.collateral = position.collateral.sub(fee);
        position.entryFundingRate = cumulativeFundingRates[_collateralToken];
        position.size = position.size.add(_sizeDelta);

        require(position.size > 0, "Vault: invalid position.size");
        _validatePosition(position.size, position.collateral);
        validateLiquidation(_account, _collateralToken, _indexToken, _isLong, true);

        // reserve tokens to pay profits on the position
        uint256 reserveDelta = usdToTokenMax(_collateralToken, _sizeDelta);
        position.reserveAmount = position.reserveAmount.add(reserveDelta);
        _increaseReservedAmount(_collateralToken, reserveDelta);

        if (_isLong) {
            // add the fee as it has been subtracted from the collateral
            _increaseGuaranteedUsd(_collateralToken, _sizeDelta.add(fee));
            _decreaseGuaranteedUsd(_collateralToken, collateralDeltaUsd);
            // treat the deposited collateral as part of the pool
            _increasePoolAmount(_collateralToken, collateralDelta);
            // fees need to be deducted from the pool since collateral is treated as part of the pool
            _decreasePoolAmount(_collateralToken, usdToTokenMin(_collateralToken, fee));
        }

        emit IncreasePosition(key, _account, _collateralToken, _indexToken, _sizeDelta, _isLong);
        emit UpdatePosition(key, position.size, position.collateral, position.averagePrice, position.entryFundingRate, position.reserveAmount);
    }

    function decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external override nonReentrant returns (uint256) {
        _validateRouter(_account);
        _validateTokens(_collateralToken, _indexToken, _isLong);
        updateCumulativeFundingRate(_collateralToken);

        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position storage position = positions[key];
        require(position.size > 0, "Vault: empty position");
        require(position.size >= _sizeDelta, "Vault: position size exceeded");

        uint256 collateral = position.collateral;
        // scrop variables to avoid stack too deep errors
        {
        uint256 reserveDelta = position.reserveAmount.mul(_sizeDelta).div(position.size);
        position.reserveAmount = position.reserveAmount.sub(reserveDelta);
        _decreaseReservedAmount(_collateralToken, reserveDelta);
        }

        (uint256 usdOut, uint256 usdOutAfterFee) = _reduceCollateral(_account, _collateralToken, _indexToken, _collateralDelta, _sizeDelta, _isLong);

        if (position.size != _sizeDelta) {
            position.entryFundingRate = cumulativeFundingRates[_collateralToken];
            position.size = position.size.sub(_sizeDelta);

            _validatePosition(position.size, position.collateral);
            validateLiquidation(_account, _collateralToken, _indexToken, _isLong, true);

            if (_isLong) {
                _increaseGuaranteedUsd(_collateralToken, collateral.sub(position.collateral));
                _decreaseGuaranteedUsd(_collateralToken, _sizeDelta);
            }
        } else {
            if (_isLong) {
                _increaseGuaranteedUsd(_collateralToken, collateral);
                _decreaseGuaranteedUsd(_collateralToken, _sizeDelta);
            }
            delete positions[key];
        }

        emit DecreasePosition(key, _account, _collateralToken, _indexToken, _collateralDelta, _sizeDelta, _isLong);
        emit UpdatePosition(key, position.size, position.collateral, position.averagePrice, position.entryFundingRate, position.reserveAmount);

        if (usdOut > 0) {
            if (_isLong) {
                _decreasePoolAmount(_collateralToken, usdToTokenMin(_collateralToken, usdOut));
            }
            uint256 amountOutAfterFees = usdToTokenMin(_collateralToken, usdOutAfterFee);
            _transferOut(_collateralToken, usdToTokenMin(_collateralToken, usdOutAfterFee), _receiver);
            return amountOutAfterFees;
        }

        return 0;
    }

    function liquidatePosition(address _account, address _collateralToken, address _indexToken, bool _isLong, address _feeReceiver) external nonReentrant {
        _validateTokens(_collateralToken, _indexToken, _isLong);
        updateCumulativeFundingRate(_collateralToken);

        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position memory position = positions[key];
        require(position.size > 0, "Vault: empty position");

        (bool _shouldLiquidate, uint256 marginFees) = validateLiquidation(_account, _collateralToken, _indexToken, _isLong, false);
        require(_shouldLiquidate, "Vault: position cannot be liquidated");

        feeReserves[_collateralToken] = feeReserves[_collateralToken].add(usdToTokenMin(_collateralToken, marginFees));

        _decreaseReservedAmount(_collateralToken, position.reserveAmount);
        if (_isLong) {
            _decreaseGuaranteedUsd(_collateralToken, position.size.sub(position.collateral));
        }

        emit LiquidatePosition(key, _account, _collateralToken, _indexToken, _isLong, position.size, position.collateral, position.reserveAmount);

        delete positions[key];

        if (!_isLong && marginFees < position.collateral) {
            uint256 remainingCollateral = position.collateral.sub(marginFees);
            _increasePoolAmount(_collateralToken, usdToTokenMin(_collateralToken, remainingCollateral));
        }

        // pay the fee receiver using the pool, we assume that in general the liquidated amount should be sufficient to cover
        // the liquidation fees
        _decreasePoolAmount(_collateralToken, usdToTokenMin(_collateralToken, liquidationFeeUsd));
        _transferOut(_collateralToken, usdToTokenMin(_collateralToken, liquidationFeeUsd), _feeReceiver);
    }

    function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) public view returns (bool, uint256) {
        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position memory position = positions[key];

        (bool hasProfit, uint256 delta) = getDelta(_indexToken, position.size, position.averagePrice, _isLong);
        uint256 marginFees = getFundingFee(_collateralToken, position.size, position.entryFundingRate);
        marginFees = marginFees.add(getPositionFee(position.size));

        if (!hasProfit && position.collateral < delta) {
            if (_raise) { revert("Vault: losses exceed collateral"); }
            return (true, marginFees);
        }

        uint256 remainingCollateral = position.collateral;
        if (!hasProfit) {
            remainingCollateral = position.collateral.sub(delta);
        }

        if (remainingCollateral < marginFees) {
            if (_raise) { revert("Vault: fees exceed collateral"); }
            // cap the fees to the remainingCollateral
            return (true, remainingCollateral);
        }

        if (remainingCollateral < marginFees.add(liquidationFeeUsd)) {
            if (_raise) { revert("Vault: liquidation fees exceed collateral"); }
            return (true, marginFees);
        }

        if (remainingCollateral.mul(maxLeverage) < position.size.mul(BASIS_POINTS_DIVISOR)) {
            if (_raise) { revert("Vault: maxLeverage exceeded"); }
            return (true, marginFees);
        }

        return (false, marginFees);
    }

    function getMaxPrice(address _token) public override view returns (uint256) {
        return getPrice(_token, true);
    }

    function getMinPrice(address _token) public override view returns (uint256) {
        return getPrice(_token, false);
    }

    function getSinglePrice(address _token) public override view returns (uint256) {
        address priceFeedAddress = priceFeeds[_token];
        require(priceFeedAddress != address(0), "Vault: invalid price feed");
        return uint256(IPriceFeed(priceFeedAddress).latestAnswer());
    }

    function getRoundId(address _token) public override view returns (uint256) {
        address priceFeedAddress = priceFeeds[_token];
        require(priceFeedAddress != address(0), "Vault: invalid price feed");
        return uint256(IPriceFeed(priceFeedAddress).latestRound());
    }

    function getRoundPrice(address _token, uint256 _roundId) public override view returns (uint256) {
        address priceFeedAddress = priceFeeds[_token];
        require(priceFeedAddress != address(0), "Vault: invalid price feed");
        require(_roundId < type(uint80).max, "Vault: invalid _roundId");
        (, int256 p, , ,) = IPriceFeed(priceFeedAddress).getRoundData(uint80(_roundId));
        return uint256(p);
    }

    function getPrice(address _token, bool _maximise) public view returns (uint256) {
        address priceFeedAddress = priceFeeds[_token];
        require(priceFeedAddress != address(0), "Vault: invalid price feed");
        IPriceFeed priceFeed = IPriceFeed(priceFeedAddress);

        uint256 price = 0;
        uint80 roundId = priceFeed.latestRound();

        for (uint80 i = 0; i < priceSampleSpace; i++) {
            if (roundId < i) { break; }
            if (roundId - i == 0) { continue; }
            (, int256 p, , ,) = priceFeed.getRoundData(roundId - i);
            require(p > 0, "Vault: invalid price");

            if (price == 0) {
                price = uint256(p);
                continue;
            }

            if (_maximise && uint256(p) > price) {
                price = uint256(p);
            }

            if (!_maximise && uint256(p) < price) {
                price = uint256(p);
            }
        }

        require(price > 0, "Vault: could not fetch price");
        // normalise price precision
        return price.mul(PRICE_PRECISION).div(getPricePrecision(_token));
    }

    function getPricePrecision(address _token) public view returns (uint256) {
        uint256 decimals = priceDecimals[_token];
        return 10 ** decimals;
    }

    function getRedemptionAmount(address _token, uint256 _usdgAmount) public override view returns (uint256) {
        uint256 price = getMaxPrice(_token);
        // calculate the price based redemption amount
        uint256 redemptionAmount = _usdgAmount.mul(PRICE_PRECISION).div(price);

        if (stableTokens[_token]) {
            return redemptionAmount;
        }

        uint256 redemptionCollateral = getRedemptionCollateral(_token);
        if (redemptionCollateral == 0) { return 0; }

        uint256 totalUsdgAmount = usdgAmounts[_token];

        // if there is no USDG debt then the redemption amount based just on price can be supported
        if (totalUsdgAmount == 0) {
            return redemptionAmount;
        }

        // calculate the cappedAmount based on the amount of backing collateral and the
        // total debt in USDG tokens for the asset
        uint256 cappedAmount = _usdgAmount.mul(redemptionCollateral).div(totalUsdgAmount);
        uint256 basisPoints = getRedemptionBasisPoints(_token);
        cappedAmount = cappedAmount.mul(basisPoints).div(BASIS_POINTS_DIVISOR);
        cappedAmount = adjustForDecimals(cappedAmount, usdg, _token);

        return cappedAmount < redemptionAmount ? cappedAmount : redemptionAmount;
    }

    function getRedemptionCollateral(address _token) public view returns (uint256) {
        if (stableTokens[_token]) {
            return poolAmounts[_token];
        }
        uint256 collateral = usdToTokenMin(_token, guaranteedUsd[_token]);
        return collateral.add(poolAmounts[_token]).sub(reservedAmounts[_token]);
    }

    function getRedemptionCollateralUsd(address _token) public view returns (uint256) {
        return tokenToUsdMin(_token, getRedemptionCollateral(_token));
    }

    function getRedemptionBasisPoints(address _token) public view returns (uint256) {
        uint256 basisPoints = redemptionBasisPoints[_token];
        require(basisPoints > 0, "Vault: invalid redemption basis points");
        return basisPoints;
    }

    function adjustForDecimals(uint256 _amount, address _tokenDiv, address _tokenMul) public view returns (uint256) {
        uint256 decimalsDiv = _tokenDiv == usdg ? USDG_DECIMALS : tokenDecimals[_tokenDiv];
        uint256 decimalsMul = _tokenMul == usdg ? USDG_DECIMALS : tokenDecimals[_tokenMul];
        return _amount.mul(10 ** decimalsMul).div(10 ** decimalsDiv);
    }

    function availableReserve(address _token) public view returns (uint256) {
        uint256 balance = IERC20(_token).balanceOf(address(this));
        return balance.sub(reservedAmounts[_token]);
    }

    function tokenToUsdMax(address _token, uint256 _tokenAmount) public view returns (uint256) {
        if (_tokenAmount == 0) { return 0; }
        uint256 price = getMaxPrice(_token);
        uint256 decimals = tokenDecimals[_token];
        return _tokenAmount.mul(price).div(10 ** decimals);
    }

    function tokenToUsdMin(address _token, uint256 _tokenAmount) public view returns (uint256) {
        if (_tokenAmount == 0) { return 0; }
        uint256 price = getMinPrice(_token);
        uint256 decimals = tokenDecimals[_token];
        return _tokenAmount.mul(price).div(10 ** decimals);
    }

    function usdToTokenMax(address _token, uint256 _usdAmount) public view returns (uint256) {
        if (_usdAmount == 0) { return 0; }
        return usdToToken(_token, _usdAmount, getMinPrice(_token));
    }

    function usdToTokenMin(address _token, uint256 _usdAmount) public view returns (uint256) {
        if (_usdAmount == 0) { return 0; }
        return usdToToken(_token, _usdAmount, getMaxPrice(_token));
    }

    function usdToToken(address _token, uint256 _usdAmount, uint256 _price) public view returns (uint256) {
        if (_usdAmount == 0) { return 0; }
        uint256 decimals = tokenDecimals[_token];
        return _usdAmount.mul(10 ** decimals).div(_price);
    }

    function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong) public override view returns (uint256, uint256, uint256, uint256, uint256, uint256, bool) {
        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position memory position = positions[key];
        uint256 realisedPnl = position.realisedPnl > 0 ? uint256(position.realisedPnl) : uint256(-position.realisedPnl);
        return (position.size, position.collateral, position.averagePrice, position.entryFundingRate, position.reserveAmount, realisedPnl, position.realisedPnl >= 0);
    }

    function getPositionKey(address _account, address _collateralToken, address _indexToken, bool _isLong) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(
            _account,
            _collateralToken,
            _indexToken,
            _isLong
        ));
    }

    function updateCumulativeFundingRate(address _token) public {
        if (lastFundingTimes[_token] == 0) {
            lastFundingTimes[_token] = block.timestamp.div(fundingInterval).mul(fundingInterval);
            return;
        }

        if (lastFundingTimes[_token].add(fundingInterval) > block.timestamp) {
            return;
        }

        uint256 fundingRate = getNextFundingRate(_token);
        cumulativeFundingRates[_token] = cumulativeFundingRates[_token].add(fundingRate);
        lastFundingTimes[_token] = block.timestamp.div(fundingInterval).mul(fundingInterval);

        emit UpdateFundingRate(_token, cumulativeFundingRates[_token]);
    }

    function getNextFundingRate(address _token) public override view returns (uint256) {
        if (lastFundingTimes[_token].add(fundingInterval) > block.timestamp) { return 0; }

        uint256 intervals = block.timestamp.sub(lastFundingTimes[_token]).div(fundingInterval);
        uint256 poolAmount = poolAmounts[_token];
        if (poolAmount == 0) { return 0; }

        return fundingRateFactor.mul(reservedAmounts[_token]).mul(intervals).div(poolAmount);
    }

    function getUtilisation(address _token) public view returns (uint256) {
        uint256 poolAmount = poolAmounts[_token];
        if (poolAmount == 0) { return 0; }

        return reservedAmounts[_token].mul(FUNDING_RATE_PRECISION).div(poolAmount);
    }

    function getPositionLeverage(address _account, address _collateralToken, address _indexToken, bool _isLong) public view returns (uint256) {
        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position memory position = positions[key];
        require(position.collateral > 0, "Vault: invalid position");
        return position.size.mul(BASIS_POINTS_DIVISOR).div(position.collateral);
    }

    function getNextAveragePrice(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong, uint256 _nextPrice, uint256 _sizeDelta) public view returns (uint256) {
        (bool hasProfit, uint256 delta) = getDelta(_indexToken, _size, _averagePrice, _isLong);
        uint256 nextSize = _size.add(_sizeDelta);
        uint256 divisor = hasProfit ? nextSize.add(delta) : nextSize.sub(delta);
        return _nextPrice.mul(nextSize).div(divisor);
    }

    function getPositionDelta(address _account, address _collateralToken, address _indexToken, bool _isLong) public view returns (bool, uint256) {
        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position memory position = positions[key];
        return getDelta(_indexToken, position.size, position.averagePrice, _isLong);
    }

    function getDelta(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong) public override view returns (bool, uint256) {
        require(_averagePrice > 0, "Vault: invalid _averagePrice");
        uint256 price = _isLong ? getMinPrice(_indexToken) : getMaxPrice(_indexToken);
        uint256 priceDelta = _averagePrice > price ? _averagePrice.sub(price) : price.sub(_averagePrice);
        uint256 delta = _size.mul(priceDelta).div(_averagePrice);

        bool hasProfit;

        if (_isLong) {
            hasProfit = price > _averagePrice;
        } else {
            hasProfit = _averagePrice > price;
        }

        // the profit is zero-ed out if the minimum % of profit is not reached
        // this helps to prevent front-running issues
        uint256 minBps = minProfitBasisPoints[_indexToken];
        if (hasProfit && delta.mul(BASIS_POINTS_DIVISOR) <= _size.mul(minBps)) {
            delta = 0;
        }

        return (hasProfit, delta);
    }

    function getFundingFee(address _token, uint256 _size, uint256 _entryFundingRate) public view returns (uint256) {
        if (_size == 0) { return 0; }

        uint256 fundingRate = cumulativeFundingRates[_token].sub(_entryFundingRate);
        if (fundingRate == 0) { return 0; }

        uint256 fundingFee = _size.mul(fundingRate).div(FUNDING_RATE_PRECISION);
        return fundingFee;
    }

    function getPositionFee(uint256 _sizeDelta) public view returns (uint256) {
        if (_sizeDelta == 0) { return 0; }
        uint256 afterFeeUsd = _sizeDelta.mul(BASIS_POINTS_DIVISOR.sub(marginFeeBasisPoints)).div(BASIS_POINTS_DIVISOR);
        return _sizeDelta.sub(afterFeeUsd);
    }

    function _reduceCollateral(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong) private returns (uint256, uint256) {
        bytes32 key = getPositionKey(_account, _collateralToken, _indexToken, _isLong);
        Position storage position = positions[key];

        uint256 fee = _collectMarginFees(_collateralToken, _sizeDelta, position.size, position.entryFundingRate);
        bool hasProfit;
        uint256 adjustedDelta;

        // scope variables to avoid stack too deep errors
        {
        (bool _hasProfit, uint256 delta) = getDelta(_indexToken, position.size, position.averagePrice, _isLong);
        hasProfit = _hasProfit;
        // get the proportional change in pnl
        adjustedDelta = _sizeDelta.mul(delta).div(position.size);
        }

        uint256 usdOut;
        // transfer profits out
        if (hasProfit && adjustedDelta > 0) {
            usdOut = adjustedDelta;
            position.realisedPnl = position.realisedPnl + int256(adjustedDelta);

            // pay out realised profits from the pool amount for short positions
            if (!_isLong) {
                uint256 tokenAmount = usdToTokenMin(_collateralToken, adjustedDelta);
                _decreasePoolAmount(_collateralToken, tokenAmount);
            }
        }

        if (!hasProfit && adjustedDelta > 0) {
            position.collateral = position.collateral.sub(adjustedDelta);

            // transfer realised losses to the pool for short positions
            // realised losses for long positions are not transferred here as
            // _increasePoolAmount was already called in increasePosition for longs
            if (!_isLong) {
                uint256 tokenAmount = usdToTokenMin(_collateralToken, adjustedDelta);
                _increasePoolAmount(_collateralToken, tokenAmount);
            }

            position.realisedPnl = position.realisedPnl - int256(adjustedDelta);
        }

        // reduce the position's collateral by _collateralDelta
        // transfer _collateralDelta out
        if (_collateralDelta > 0) {
            usdOut = usdOut.add(_collateralDelta);
            position.collateral = position.collateral.sub(_collateralDelta);
        }

        // if the position will be closed, then transfer the remaining collateral out
        if (position.size == _sizeDelta) {
            usdOut = usdOut.add(position.collateral);
            position.collateral = 0;
        }

        // if the usdOut is more than the fee then deduct the fee from the usdOut directly
        // else deduct the fee from the position's collateral
        uint256 usdOutAfterFee = usdOut;
        if (usdOut > fee) {
            usdOutAfterFee = usdOut.sub(fee);
        } else {
            position.collateral = position.collateral.sub(fee);
            if (_isLong) {
                uint256 feeTokens = usdToTokenMin(_collateralToken, fee);
                _decreasePoolAmount(_collateralToken, feeTokens);
            }
        }

        emit UpdatePnl(key, hasProfit, adjustedDelta);

        return (usdOut, usdOutAfterFee);
    }

    function _validatePosition(uint256 _size, uint256 _collateral) private pure {
        if (_size == 0) {
            require(_collateral == 0, "Vault: collateral should be withdrawn");
            return;
        }
        require(_size >= _collateral, "Vault: _size must be more than _collateral");
    }

    function _validateRouter(address _account) private view {
        if (msg.sender == _account) { return; }
        if (msg.sender == router) { return; }
        require(approvedRouters[_account][msg.sender], "Vault: invalid msg.sender");
    }

    function _validateTokens(address _collateralToken, address _indexToken, bool _isLong) private view {
        if (_isLong) {
            require(_collateralToken == _indexToken, "Vault: mismatched tokens");
            require(whitelistedTokens[_collateralToken], "Vault: _collateralToken not whitelisted");
            require(!stableTokens[_collateralToken], "Vault: _collateralToken must not be a stableToken");
            return;
        }

        // _indexToken is intentionally not enforced to be a whitelisted token for shorts
        // it just needs to have a valid priceFeed
        // this adds flexbility by allowing shorting on non-whitelisted tokens
        require(whitelistedTokens[_collateralToken], "Vault: _collateralToken not whitelisted");
        require(stableTokens[_collateralToken], "Vault: _collateralToken must be a stableToken");
        require(!stableTokens[_indexToken], "Vault: _indexToken must not be a stableToken");
    }

    function _collectSwapFees(address _token, uint256 _amount, bool _isStableSwap) private returns (uint256) {
        uint256 feeBasisPoints = _isStableSwap ? stableSwapFeeBasisPoints : swapFeeBasisPoints;
        uint256 afterFeeAmount = _amount.mul(BASIS_POINTS_DIVISOR.sub(feeBasisPoints)).div(BASIS_POINTS_DIVISOR);
        uint256 feeAmount = _amount.sub(afterFeeAmount);
        feeReserves[_token] = feeReserves[_token].add(feeAmount);
        emit CollectSwapFees(_token, feeAmount);
        return afterFeeAmount;
    }

    function _collectMarginFees(address _token, uint256 _sizeDelta, uint256 _size, uint256 _entryFundingRate) private returns (uint256) {
        uint256 feeUsd = getPositionFee(_sizeDelta);

        uint256 fundingFee = getFundingFee(_token, _size, _entryFundingRate);
        feeUsd = feeUsd.add(fundingFee);

        uint256 feeTokens = usdToTokenMin(_token, feeUsd);
        feeReserves[_token] = feeReserves[_token].add(feeTokens);

        emit CollectMarginFees(_token, feeUsd, feeTokens);
        return feeUsd;
    }

    function _transferIn(address _token) private returns (uint256) {
        uint256 prevBalance = tokenBalances[_token];
        uint256 nextBalance = IERC20(_token).balanceOf(address(this));
        tokenBalances[_token] = nextBalance;

        return nextBalance.sub(prevBalance);
    }

    function _transferOut(address _token, uint256 _amount, address _receiver) private {
        IERC20(_token).safeTransfer(_receiver, _amount);
        tokenBalances[_token] = IERC20(_token).balanceOf(address(this));
    }

    function _updateTokenBalance(address _token) private {
        uint256 nextBalance = IERC20(_token).balanceOf(address(this));
        tokenBalances[_token] = nextBalance;
    }

    function _increasePoolAmount(address _token, uint256 _amount) private {
        poolAmounts[_token] = poolAmounts[_token].add(_amount);
        uint256 balance = IERC20(_token).balanceOf(address(this));
        require(poolAmounts[_token] <= balance, "Vault: invalid increase");
        emit IncreasePoolAmount(_token, _amount);
    }

    function _decreasePoolAmount(address _token, uint256 _amount) private {
        poolAmounts[_token] = poolAmounts[_token].sub(_amount, "Vault: poolAmount exceeded");
        require(reservedAmounts[_token] <= poolAmounts[_token], "Vault: reserve exceeds pool");
        emit DecreasePoolAmount(_token, _amount);
    }

    function _increaseUsdgAmount(address _token, uint256 _amount) private {
        usdgAmounts[_token] = usdgAmounts[_token].add(_amount);
        emit IncreaseUsdgAmount(_token, _amount);
    }

    function _decreaseUsdgAmount(address _token, uint256 _amount) private {
        uint256 value = usdgAmounts[_token];
        // since USDG can be minted using multiple assets
        // it is possible for the USDG debt for a single asset to be less than zero
        // the USDG debt is capped to zero for this case
        if (value <= _amount) {
            usdgAmounts[_token] = 0;
            emit DecreaseUsdgAmount(_token, value);
            return;
        }
        usdgAmounts[_token] = value.sub(_amount);
        emit DecreaseUsdgAmount(_token, _amount);
    }

    function _increaseReservedAmount(address _token, uint256 _amount) private {
        reservedAmounts[_token] = reservedAmounts[_token].add(_amount);
        require(reservedAmounts[_token] <= poolAmounts[_token], "Vault: reserve exceeds pool");
        emit IncreaseReservedAmount(_token, _amount);
    }

    function _decreaseReservedAmount(address _token, uint256 _amount) private {
        reservedAmounts[_token] = reservedAmounts[_token].sub(_amount, "Vault: insufficient reserve");
        emit DecreaseReservedAmount(_token, _amount);
    }

    function _increaseGuaranteedUsd(address _token, uint256 _usdAmount) private {
        guaranteedUsd[_token] = guaranteedUsd[_token].add(_usdAmount);
        emit IncreaseGuaranteedUsd(_token, _usdAmount);
    }

    function _decreaseGuaranteedUsd(address _token, uint256 _usdAmount) private {
        guaranteedUsd[_token] = guaranteedUsd[_token].sub(_usdAmount);
        emit DecreaseGuaranteedUsd(_token, _usdAmount);
    }
}

File 2 of 9 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

File 3 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

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

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

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

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

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

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

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

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

File 4 of 9 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

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

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

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

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

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

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

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

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

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

File 5 of 9 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

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

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

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

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

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

        _;

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

File 6 of 9 : IPriceFeed.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

interface IPriceFeed {
    function description() external view returns (string memory);
    function aggregator() external view returns (address);
    function latestAnswer() external view returns (int256);
    function latestRound() external view returns (uint80);
    function getRoundData(uint80 roundId) external view returns (uint80, int256, uint256, uint256, uint80);
}

File 7 of 9 : IUSDG.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

interface IUSDG {
    function mint(address _account, uint256 _amount) external;
    function burn(address _account, uint256 _amount) external;
}

File 8 of 9 : IVault.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;

interface IVault {
    function buyUSDG(address _token, address _receiver) external returns (uint256);
    function sellUSDG(address _token, address _receiver) external returns (uint256);
    function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);
    function increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external;
    function decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external returns (uint256);

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

    function poolAmounts(address _token) external view returns (uint256);
    function reservedAmounts(address _token) external view returns (uint256);
    function usdgAmounts(address _token) external view returns (uint256);
    function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);
    function getMaxPrice(address _token) external view returns (uint256);
    function getMinPrice(address _token) external view returns (uint256);
    function getSinglePrice(address _token) external view returns (uint256);
    function getRoundId(address _token) external view returns (uint256);
    function getRoundPrice(address _token, uint256 _roundId) external view returns (uint256);

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

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

pragma solidity ^0.6.2;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdgAmount","type":"uint256"}],"name":"BuyUSDG","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeUsd","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeTokens","type":"uint256"}],"name":"CollectMarginFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"CollectSwapFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DecreaseGuaranteedUsd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DecreasePoolAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"collateralToken","type":"address"},{"indexed":false,"internalType":"address","name":"indexToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sizeDelta","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"}],"name":"DecreasePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DecreaseReservedAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DecreaseUsdgAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreaseGuaranteedUsd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreasePoolAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"collateralToken","type":"address"},{"indexed":false,"internalType":"address","name":"indexToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sizeDelta","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"}],"name":"IncreasePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreaseReservedAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncreaseUsdgAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"collateralToken","type":"address"},{"indexed":false,"internalType":"address","name":"indexToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserveAmount","type":"uint256"}],"name":"LiquidatePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"usdgAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"SellUSDG","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundingRate","type":"uint256"}],"name":"UpdateFundingRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"hasProfit","type":"bool"},{"indexed":false,"internalType":"uint256","name":"delta","type":"uint256"}],"name":"UpdatePnl","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"averagePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entryFundingRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserveAmount","type":"uint256"}],"name":"UpdatePosition","type":"event"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"addRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenDiv","type":"address"},{"internalType":"address","name":"_tokenMul","type":"address"}],"name":"adjustForDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"approvedRouters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"availableReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"buyUSDG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"clearTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cumulativeFundingRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_collateralDelta","type":"uint256"},{"internalType":"uint256","name":"_sizeDelta","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"decreasePosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feeReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingRateFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_averagePrice","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getDelta","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_entryFundingRate","type":"uint256"}],"name":"getFundingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getMaxPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getMinPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_averagePrice","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"uint256","name":"_nextPrice","type":"uint256"},{"internalType":"uint256","name":"_sizeDelta","type":"uint256"}],"name":"getNextAveragePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getNextFundingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPositionDelta","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sizeDelta","type":"uint256"}],"name":"getPositionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPositionKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"getPositionLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_maximise","type":"bool"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getPricePrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdgAmount","type":"uint256"}],"name":"getRedemptionAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getRedemptionBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getRedemptionCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getRedemptionCollateralUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_roundId","type":"uint256"}],"name":"getRoundPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getSinglePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getUtilisation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gov","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"guaranteedUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"uint256","name":"_sizeDelta","type":"uint256"},{"internalType":"bool","name":"_isLong","type":"bool"}],"name":"increasePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"},{"internalType":"address","name":"_usdg","type":"address"},{"internalType":"uint256","name":"_maxUsdg","type":"uint256"},{"internalType":"uint256","name":"_liquidationFeeUsd","type":"uint256"},{"internalType":"uint256","name":"_fundingRateFactor","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastFundingTimes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"liquidatePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationFeeUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marginFeeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxUsdg","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minProfitBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positions","outputs":[{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"averagePrice","type":"uint256"},{"internalType":"uint256","name":"entryFundingRate","type":"uint256"},{"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"internalType":"int256","name":"realisedPnl","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"priceDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"priceFeeds","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceSampleSpace","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redemptionBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"removeRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reservedAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"sellUSDG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_swapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_stableSwapFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_marginFeeBasisPoints","type":"uint256"},{"internalType":"uint256","name":"_liquidationFeeUsd","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fundingInterval","type":"uint256"},{"internalType":"uint256","name":"_fundingRateFactor","type":"uint256"}],"name":"setFundingRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_gov","type":"address"}],"name":"setGov","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLeverage","type":"uint256"}],"name":"setMaxLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxUsdg","type":"uint256"}],"name":"setMaxUsdg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_priceSampleSpace","type":"uint256"}],"name":"setPriceSampleSpace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"uint256","name":"_priceDecimals","type":"uint256"},{"internalType":"uint256","name":"_tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"_redemptionBps","type":"uint256"},{"internalType":"uint256","name":"_minProfitBps","type":"uint256"},{"internalType":"bool","name":"_isStable","type":"bool"}],"name":"setTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stableSwapFeeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stableTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapFeeBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"tokenToUsdMax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"tokenToUsdMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"updateCumulativeFundingRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdAmount","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"usdToToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdAmount","type":"uint256"}],"name":"usdToTokenMax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_usdAmount","type":"uint256"}],"name":"usdToTokenMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdg","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"usdgAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_indexToken","type":"address"},{"internalType":"bool","name":"_isLong","type":"bool"},{"internalType":"bool","name":"_raise","type":"bool"}],"name":"validateLiquidation","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdrawFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

60806040526207a1206005556003600655601e6008556004600955600a8055617080600b5534801561003057600080fd5b506001600055600380546001600160a01b03191633179055615cfc80620000586000396000f3fe608060405234801561001057600080fd5b506004361061046a5760003560e01c8063815b3c741161024c578063c65bc7b111610146578063de2ea948116100c3578063f07456ce11610087578063f07456ce14611078578063f25552781461109e578063f5b91b7b146110cc578063f887ea40146110d4578063fa12dbc0146110dc5761046a565b8063de2ea94814610fb6578063df73a26714610ffe578063e124e6d214611006578063e62b39801461102c578063e67f59a7146110525761046a565b8063d13f90b41161010a578063d13f90b414610ec5578063d3127e6314610f07578063d54d5a9f14610f24578063d8f897c314610f6a578063daf9c21014610f905761046a565b8063c65bc7b114610e04578063c896926114610e2a578063cc5b814414610e47578063cefe0f2114610e79578063cfad57a214610e9f5761046a565b80639899cd02116101d4578063a9af372d11610198578063a9af372d14610d62578063ae3302c214610da8578063b136ca4914610db0578063c3c7b9e914610dd6578063c4f718bf14610dfc5761046a565b80639899cd0214610cb65780639dcb511a14610ce2578063a22f239214610d08578063a42ab3d214610d10578063a93acac214610d3c5761046a565b806385c092051161021b57806385c0920514610c0457806388b1fbdf14610c2a5780638ee573ac14610c505780639331621214610c765780639849e41214610cae5761046a565b8063815b3c7414610b36578063817bb85714610b5c57806381a612d614610b8a57806382a0849014610bb05761046a565b806341f68d291161036857806358bcdaa6116102e55780636fcba377116102a95780636fcba37714610a59578063711e619014610a8857806376d6976014610ab65780637933dd0a14610ae45780637ca8c69914610b0a5761046a565b806358bcdaa6146109a057806360922199146109c35780636a7bc8b4146109f15780636ae0b15414610a2b5780636fc8070814610a515761046a565b80634a3f088d1161032c5780634a3f088d1461084e578063514ea4bf146108c657806351723e8214610916578063523fba7f1461095457806352f55eed1461097a5761046a565b806341f68d291461074f578063421528731461075757806342b60b031461078b57806345a6f370146107b157806348d91abf1461080a5761046a565b80631ce9cb8f116103f65780632d4b0576116103ba5780632d4b0576146106aa5780632fa03b8f146106e8578063318bc68914610705578063364add4e1461070d578063392e53cd146107335761046a565b80631ce9cb8f146105e657806324ca984e1461060c5780632709c7d91461063257806329ff9615146106585780632c668ec11461067e5761046a565b806313f1e7361161043d57806313f1e73614610549578063174d26941461056f57806317bbf25c14610577578063180cd03f146105945780631aa4ace5146105c05761046a565b806304fef1db1461046f5780630a48d5a9146104a75780630d62516c146104d357806312d43a5114610525575b600080fd5b6104956004803603602081101561048557600080fd5b50356001600160a01b031661110e565b60408051918252519081900360200190f35b610495600480360360408110156104bd57600080fd5b506001600160a01b038135169060200135611171565b610523600480360360e08110156104e957600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060808101359060a08101359060c0013515156111c4565b005b61052d6112fa565b604080516001600160a01b039092168252519081900360200190f35b6105236004803603602081101561055f57600080fd5b50356001600160a01b0316611309565b61049561144c565b6104956004803603602081101561058d57600080fd5b5035611452565b610495600480360360408110156105aa57600080fd5b506001600160a01b038135169060200135611496565b610495600480360360208110156105d657600080fd5b50356001600160a01b03166115e3565b610495600480360360208110156105fc57600080fd5b50356001600160a01b03166115f5565b6105236004803603602081101561062257600080fd5b50356001600160a01b0316611607565b6104956004803603602081101561064857600080fd5b50356001600160a01b0316611638565b6104956004803603602081101561066e57600080fd5b50356001600160a01b031661170f565b6104956004803603604081101561069457600080fd5b506001600160a01b038135169060200135611723565b610495600480360360808110156106c057600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135151561182b565b610523600480360360208110156106fe57600080fd5b5035611886565b610495611982565b6104956004803603602081101561072357600080fd5b50356001600160a01b0316611988565b61073b6119a6565b604080519115158252519081900360200190f35b6104956119af565b6104956004803603606081101561076d57600080fd5b508035906001600160a01b03602082013581169160400135166119b5565b61073b600480360360208110156107a157600080fd5b50356001600160a01b0316611a57565b6107ef600480360360808110156107c757600080fd5b506001600160a01b038135811691602081013582169160408201351690606001351515611a6c565b60408051921515835260208301919091528051918290030190f35b610523600480360360a081101561082057600080fd5b506001600160a01b038135811691602081013582169160408201351690606081013590608001351515611af9565b61088c6004803603608081101561086457600080fd5b506001600160a01b038135811691602081013582169160408201351690606001351515611e63565b604080519788526020880196909652868601949094526060860192909252608085015260a0840152151560c0830152519081900360e00190f35b6108e3600480360360208110156108dc57600080fd5b5035611f37565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6104956004803603608081101561092c57600080fd5b506001600160a01b038135811691602081013582169160408201351690606001351515611f6c565b6104956004803603602081101561096a57600080fd5b50356001600160a01b031661204c565b6104956004803603602081101561099057600080fd5b50356001600160a01b031661205e565b610523600480360360408110156109b657600080fd5b5080359060200135612070565b61073b600480360360408110156109d957600080fd5b506001600160a01b03813581169160200135166121b4565b6107ef60048036036080811015610a0757600080fd5b506001600160a01b03813516906020810135906040810135906060013515156121d4565b61052360048036036020811015610a4157600080fd5b50356001600160a01b03166122eb565b610495612319565b61052360048036036080811015610a6f57600080fd5b508035906020810135906040810135906060013561231f565b61049560048036036040811015610a9e57600080fd5b506001600160a01b03813581169160200135166124e2565b61049560048036036040811015610acc57600080fd5b506001600160a01b03813516906020013515156127ea565b61049560048036036020811015610afa57600080fd5b50356001600160a01b0316612a96565b61049560048036036040811015610b2057600080fd5b506001600160a01b038135169060200135612aa8565b61049560048036036020811015610b4c57600080fd5b50356001600160a01b0316612ac2565b61049560048036036040811015610b7257600080fd5b506001600160a01b0381358116916020013516612b65565b61049560048036036020811015610ba057600080fd5b50356001600160a01b0316612f02565b610495600480360360e0811015610bc657600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359160808201359160a081013515159160c09091013516612f0f565b61049560048036036020811015610c1a57600080fd5b50356001600160a01b03166132af565b61049560048036036020811015610c4057600080fd5b50356001600160a01b031661338f565b61049560048036036020811015610c6657600080fd5b50356001600160a01b03166133a1565b61049560048036036060811015610c8c57600080fd5b506001600160a01b0381358116916020810135821691604090910135166133b3565b6104956136cc565b61049560048036036040811015610ccc57600080fd5b506001600160a01b0381351690602001356136d2565b61052d60048036036020811015610cf857600080fd5b50356001600160a01b03166136f4565b61049561370f565b61049560048036036040811015610d2657600080fd5b506001600160a01b038135169060200135613715565b61049560048036036020811015610d5257600080fd5b50356001600160a01b0316613732565b610495600480360360c0811015610d7857600080fd5b506001600160a01b0381351690602081013590604081013590606081013515159060808101359060a001356137fb565b61049561385e565b61049560048036036020811015610dc657600080fd5b50356001600160a01b0316613864565b61049560048036036020811015610dec57600080fd5b50356001600160a01b0316613905565b610495613917565b61049560048036036020811015610e1a57600080fd5b50356001600160a01b031661391d565b61052360048036036020811015610e4057600080fd5b503561392f565b61049560048036036060811015610e5d57600080fd5b506001600160a01b0381351690602081013590604001356139d6565b61049560048036036020811015610e8f57600080fd5b50356001600160a01b0316613a2c565b61052360048036036020811015610eb557600080fd5b50356001600160a01b0316613a3e565b610523600480360360a0811015610edb57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060800135613ab2565b61052360048036036020811015610f1d57600080fd5b5035613baa565b6107ef600480360360a0811015610f3a57600080fd5b506001600160a01b0381358116916020810135821691604082013516906060810135151590608001351515613ca7565b61049560048036036020811015610f8057600080fd5b50356001600160a01b0316613f4a565b61073b60048036036020811015610fa657600080fd5b50356001600160a01b0316613f5c565b610523600480360360a0811015610fcc57600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013515159160809091013516613f71565b61049561428b565b6104956004803603602081101561101c57600080fd5b50356001600160a01b0316614291565b6104956004803603602081101561104257600080fd5b50356001600160a01b031661429e565b6105236004803603602081101561106857600080fd5b50356001600160a01b03166142f3565b6104956004803603602081101561108e57600080fd5b50356001600160a01b0316614473565b610495600480360360408110156110b457600080fd5b506001600160a01b0381358116916020013516614485565b61052d61457c565b61052d61458b565b610495600480360360608110156110f257600080fd5b506001600160a01b03813516906020810135906040013561459f565b6001600160a01b0381166000908152601760205260408120548061113657600091505061116c565b6001600160a01b03831660009081526018602052604090205461116890829061116290620f42406145e2565b9061463b565b9150505b919050565b600081611180575060006111be565b600061118b84612f02565b6001600160a01b0385166000908152601160205260409020549091506111b9600a82900a61116286856145e2565b925050505b92915050565b6002600054141561120a576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03163314611261576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6001600160a01b038781166000908152600e602090815260408083208054600160ff1991821617909155600f835281842080546001600160a01b031916958c1695909517909455601082528083208990556011825280832088905560128252808320879055601382528083208690556014909152902080549091168215151790556112eb87614291565b50506001600055505050505050565b6003546001600160a01b031681565b6001600160a01b0381166000908152601b602052604090205461135b57600b5461133d90611337428261463b565b906145e2565b6001600160a01b0382166000908152601b6020526040902055611449565b600b546001600160a01b0382166000908152601b60205260409020544291611383919061467d565b111561138e57611449565b600061139982613732565b6001600160a01b0383166000908152601a60205260409020549091506113bf908261467d565b6001600160a01b0383166000908152601a6020526040902055600b546113e990611337428261463b565b6001600160a01b0383166000818152601b6020908152604080832094909455601a8152908390205483519283529082015281517fa146fc154e1913322e9817d49f0d5c37466c24326e15de10e739a948be815eab929181900390910190a1505b50565b60075481565b6000816114615750600061116c565b600061148a612710611162611483600a546127106146d790919063ffffffff16565b86906145e2565b905061116883826146d7565b6001600160a01b038083166000908152600f602052604081205490911680611501576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081c1c9a58d94819995959603a1b604482015290519081900360640190fd5b6001600160501b03831061155c576040805162461bcd60e51b815260206004820152601760248201527f5661756c743a20696e76616c6964205f726f756e644964000000000000000000604482015290519081900360640190fd5b6000816001600160a01b0316639a6fc8f5856040518263ffffffff1660e01b815260040180826001600160501b0316815260200191505060a06040518083038186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d60a08110156115d557600080fd5b506020015195945050505050565b60166020526000908152604090205481565b601d6020526000908152604090205481565b336000908152600d602090815260408083206001600160a01b0394909416835292905220805460ff19166001179055565b6001600160a01b038082166000908152600f6020526040812054909116806116a3576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081c1c9a58d94819995959603a1b604482015290519081900360640190fd5b806001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156116dc57600080fd5b505afa1580156116f0573d6000803e3d6000fd5b505050506040513d602081101561170657600080fd5b50519392505050565b60006111be8261171e84613864565b611171565b60008061172f84614291565b9050600061174e82611162866c0c9f2c9cd04674edea400000006145e2565b6001600160a01b03861660009081526014602052604090205490915060ff161561177b5791506111be9050565b600061178686613864565b90508061179957600093505050506111be565b6001600160a01b038616600090815260166020526040902054806117c357829450505050506111be565b60006117d38261116289866145e2565b905060006117e08961429e565b90506117f261271061116284846145e2565b60025490925061180d9083906001600160a01b03168b6119b5565b915084821061181c578461181e565b815b9998505050505050505050565b604080516bffffffffffffffffffffffff19606096871b811660208084019190915295871b811660348301529390951b9092166048850152151560f81b605c8401528051603d818503018152605d9093019052815191012090565b600260005414156118cc576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03163314611923576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b60008111611978576040805162461bcd60e51b815260206004820181905260248201527f5661756c743a20696e76616c6964205f707269636553616d706c655370616365604482015290519081900360640190fd5b6006556001600055565b600a5481565b6001600160a01b0316600090815260106020526040902054600a0a90565b60015460ff1681565b60045481565b60025460009081906001600160a01b038581169116146119ed576001600160a01b0384166000908152601160205260409020546119f0565b60125b6002549091506000906001600160a01b03858116911614611a29576001600160a01b038416600090815260116020526040902054611a2c565b60125b9050611a4b82600a0a61116283600a0a896145e290919063ffffffff16565b925050505b9392505050565b60146020526000908152604090205460ff1681565b6000806000611a7d8787878761182b565b9050611a876159db565b506000818152601c6020908152604091829020825160c08101845281548082526001830154938201939093526002820154938101849052600382015460608201526004820154608082015260059091015460a082015291611aea918891886121d4565b93509350505094509492505050565b60026000541415611b3f576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b6002600055611b4d85614719565b611b588484836147c4565b611b6184611309565b6000611b6f8686868561182b565b6000818152601c6020526040812091925083611b9357611b8e86612f02565b611b9c565b611b9c86614291565b8254909150611bad57600282018190555b815415801590611bbd5750600085115b15611bde57611bd8868360000154846002015487858a6137fb565b60028301555b6000611bf48887856000015486600301546149ef565b90506000611c0189614ab3565b90506000611c0f8a83611171565b6001860154909150611c21908261467d565b60018601819055831115611c665760405162461bcd60e51b8152600401808060200182810382526027815260200180615c736027913960400191505060405180910390fd5b6001850154611c7590846146d7565b60018601556001600160a01b038a166000908152601a602052604090205460038601558454611ca4908961467d565b808655611cf8576040805162461bcd60e51b815260206004820152601c60248201527f5661756c743a20696e76616c696420706f736974696f6e2e73697a6500000000604482015290519081900360640190fd5b611d0a85600001548660010154614b60565b611d188b8b8b8a6001613ca7565b50506000611d268b8a613715565b6004870154909150611d38908261467d565b6004870155611d478b82614bea565b8715611d8757611d608b611d5b8b8761467d565b614cd0565b611d6a8b83614d4f565b611d748b84614dce565b611d878b611d828d876136d2565b614f2c565b604080518881526001600160a01b03808f166020830152808e16828401528c166060820152608081018b905289151560a082015290517f6e5cc481958dc36bc9aa19dcc8c3bcc665516bdf8d1a0d8ec2f1b1cc2c1c129f9181900360c00190a1855460018701546002880154600389015460048a0154604080518d81526020810196909652858101949094526060850192909252608084015260a0830152517f3aeb3f1829f77430a6f2f944f3f8002d509c0abaa9b58d7a8a8376de373c06509181900360c00190a15050600160005550505050505050505050565b600080600080600080600080611e7b8c8c8c8c61182b565b9050611e856159db565b506000818152601c60209081526040808320815160c0810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460808301526005015460a082018190529091908112611ef0578160a00151600003611ef6565b8160a001515b8251602084015160408501516060860151608087015160a090970151939e50919c509a50985092965094505060001315915050949950949992975094509450565b601c60205260009081526040902080546001820154600283015460038401546004850154600590950154939492939192909186565b600080611f7b8686868661182b565b9050611f856159db565b506000818152601c6020908152604091829020825160c08101845281548152600182015492810183905260028201549381019390935260038101546060840152600481015460808401526005015460a0830152612029576040805162461bcd60e51b815260206004820152601760248201527f5661756c743a20696e76616c696420706f736974696f6e000000000000000000604482015290519081900360640190fd5b602081015181516120419190611162906127106145e2565b979650505050505050565b60156020526000908152604090205481565b60176020526000908152604090205481565b600260005414156120b6576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b0316331461210d576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b610e108211612163576040805162461bcd60e51b815260206004820152601f60248201527f5661756c743a20696e76616c6964205f66756e64696e67496e74657276616c00604482015290519081900360640190fd5b6127108111156121a45760405162461bcd60e51b8152600401808060200182810382526021815260200180615b646021913960400191505060405180910390fd5b600b91909155600c556001600055565b600d60209081526000928352604080842090915290825290205460ff1681565b6000806000841161222c576040805162461bcd60e51b815260206004820152601c60248201527f5661756c743a20696e76616c6964205f61766572616765507269636500000000604482015290519081900360640190fd5b6000836122415761223c87614291565b61224a565b61224a87612f02565b905060008186116122645761225f82876146d7565b61226e565b61226e86836146d7565b90506000612280876111628a856145e2565b9050600086156122935750868311612298565b508287115b6001600160a01b038a166000908152601360205260409020548180156122d257506122c38a826145e2565b6122cf846127106145e2565b11155b156122dc57600092505b50999098509650505050505050565b336000908152600d602090815260408083206001600160a01b0394909416835292905220805460ff19169055565b60065481565b60026000541415612365576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b031633146123bc576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6101f48411156123fd5760405162461bcd60e51b8152600401808060200182810382526022815260200180615b426022913960400191505060405180910390fd5b6101f483111561243e5760405162461bcd60e51b8152600401808060200182810382526028815260200180615b856028913960400191505060405180910390fd5b6101f482111561247f5760405162461bcd60e51b8152600401808060200182810382526024815260200180615bad6024913960400191505060405180910390fd5b6d04ee2d6d415b85acef81000000008111156124cc5760405162461bcd60e51b8152600401808060200182810382526021815260200180615c026021913960400191505060405180910390fd5b600755600892909255600955600a556001600055565b60006002600054141561252a576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b600260009081556001600160a01b0384168152600e602052604090205460ff1661259b576040805162461bcd60e51b815260206004820152601d60248201527f5661756c743a205f746f6b656e206e6f742077686974656c6973746564000000604482015290519081900360640190fd5b6002546000906125b3906001600160a01b0316614ab3565b905060008111612606576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081d5cd919d05b5bdd5b9d603a1b604482015290519081900360640190fd5b61260f84611309565b600061261b8583611723565b905060008111612672576040805162461bcd60e51b815260206004820152601f60248201527f5661756c743a20696e76616c696420726564656d7074696f6e416d6f756e7400604482015290519081900360640190fd5b61267c8583615048565b6126868582614f2c565b60025460408051632770a7eb60e21b81523060048201526024810185905290516001600160a01b0390921691639dc29fac9160448082019260009290919082900301818387803b1580156126d957600080fd5b505af11580156126ed573d6000803e3d6000fd5b505050506001600160a01b03851660009081526014602052604081205461271a908790849060ff1661512a565b905060008111612771576040805162461bcd60e51b815260206004820152601a60248201527f5661756c743a20696e76616c696420746f6b656e416d6f756e74000000000000604482015290519081900360640190fd5b61277c8682876151f2565b600254612791906001600160a01b0316615299565b604080516001600160a01b03881681526020810185905280820183905290517f4dbcba0f818014df46e678078e85b6751ed487b29b86d25c7d6b512b209c05869181900360600190a1925050505b600160005592915050565b6001600160a01b038083166000908152600f602052604081205490911680612855576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081c1c9a58d94819995959603a1b604482015290519081900360640190fd5b6000819050600080826001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b15801561289657600080fd5b505afa1580156128aa573d6000803e3d6000fd5b505050506040513d60208110156128c057600080fd5b5051905060005b600654816001600160501b03161015612a1d57806001600160501b0316826001600160501b031610156128f957612a1d565b6001600160501b038183031661290e57612a15565b6000846001600160a01b0316639a6fc8f58385036040518263ffffffff1660e01b815260040180826001600160501b0316815260200191505060a06040518083038186803b15801561295f57600080fd5b505afa158015612973573d6000803e3d6000fd5b505050506040513d60a081101561298957600080fd5b50602001519050600081136129dc576040805162461bcd60e51b81526020600482015260146024820152735661756c743a20696e76616c696420707269636560601b604482015290519081900360640190fd5b836129e8579250612a15565b8780156129f457508381115b156129fd578093505b87158015612a0a57508381105b15612a13578093505b505b6001016128c7565b5060008211612a73576040805162461bcd60e51b815260206004820152601c60248201527f5661756c743a20636f756c64206e6f7420666574636820707269636500000000604482015290519081900360640190fd5b612041612a7f88611988565b611162846c0c9f2c9cd04674edea400000006145e2565b60126020526000908152604090205481565b600081612ab7575060006111be565b600061118b84614291565b600080826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612b1257600080fd5b505afa158015612b26573d6000803e3d6000fd5b505050506040513d6020811015612b3c57600080fd5b50516001600160a01b0384166000908152601860205260409020549091506111689082906146d7565b600060026000541415612bad576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b600260009081556001600160a01b0384168152600e602052604090205460ff16612c1e576040805162461bcd60e51b815260206004820152601d60248201527f5661756c743a205f746f6b656e206e6f742077686974656c6973746564000000604482015290519081900360640190fd5b6000612c2984614ab3565b905060008111612c80576040805162461bcd60e51b815260206004820152601a60248201527f5661756c743a20696e76616c696420746f6b656e416d6f756e74000000000000604482015290519081900360640190fd5b612c8984611309565b6000612c9485612f02565b6001600160a01b03861660009081526014602052604081205491925090612cc1908790859060ff1661512a565b90506000612ce06c0c9f2c9cd04674edea4000000061116284866145e2565b600254909150612cfc90829089906001600160a01b03166119b5565b905060008111612d4f576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081d5cd919d05b5bdd5b9d603a1b604482015290519081900360640190fd5b600454612dd682600260009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612da457600080fd5b505afa158015612db8573d6000803e3d6000fd5b505050506040513d6020811015612dce57600080fd5b50519061467d565b1115612e29576040805162461bcd60e51b815260206004820152601760248201527f5661756c743a206d617855736467206578636565646564000000000000000000604482015290519081900360640190fd5b600254604080516340c10f1960e01b81526001600160a01b03898116600483015260248201859052915191909216916340c10f1991604480830192600092919082900301818387803b158015612e7e57600080fd5b505af1158015612e92573d6000803e3d6000fd5b50505050612ea08782615334565b612eaa8783614dce565b604080516001600160a01b03891681526020810186905280820183905290517fcb7695fabc26132829a47896aa122101baca9fe5838c8f69dc912f674b320dfa9181900360600190a160016000559695505050505050565b60006111be8260006127ea565b600060026000541415612f57576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b6002600055612f6588614719565b612f708787856147c4565b612f7987611309565b6000612f878989898761182b565b6000818152601c60205260409020805491925090612fe4576040805162461bcd60e51b81526020600482015260156024820152742b30bab63a1d1032b6b83a3c903837b9b4ba34b7b760591b604482015290519081900360640190fd5b805486111561303a576040805162461bcd60e51b815260206004820152601d60248201527f5661756c743a20706f736974696f6e2073697a65206578636565646564000000604482015290519081900360640190fd5b60018101548154600483015460009161305791611162908b6145e2565b600484015490915061306990826146d7565b60048401556130788b826153b3565b5060008061308a8d8d8d8d8d8d61546a565b855491935091508914613113576001600160a01b038c166000908152601a6020526040902054600385015583546130c1908a6146d7565b80855560018501546130d39190614b60565b6130e18d8d8d8b6001613ca7565b5050871561310e576131048c611d5b8660010154866146d790919063ffffffff16565b61310e8c8a614d4f565b61315f565b871561312d576131238c84614cd0565b61312d8c8a614d4f565b6000858152601c6020526040812081815560018101829055600281018290556003810182905560048101829055600501555b7f4eaeb7f662a174e44c3d1fbe91a1ee412dcc205fa98c31c03b413bd4d0b829d4858e8e8e8e8e8e60405180888152602001876001600160a01b03168152602001866001600160a01b03168152602001856001600160a01b03168152602001848152602001838152602001821515815260200197505050505050505060405180910390a183546001850154600286015460038701546004880154604080518b81526020810196909652858101949094526060850192909252608084015260a0830152517f3aeb3f1829f77430a6f2f944f3f8002d509c0abaa9b58d7a8a8376de373c06509181900360c00190a18115613295578715613266576132668c611d828e856136d2565b60006132728d836136d2565b90506132888d6132828f856136d2565b8a6151f2565b955061329f945050505050565b6000955050505050505b6001600055979650505050505050565b6001600160a01b038082166000908152600f60205260408120549091168061331a576040805162461bcd60e51b815260206004820152601960248201527815985d5b1d0e881a5b9d985b1a59081c1c9a58d94819995959603a1b604482015290519081900360640190fd5b806001600160a01b031663668a0f026040518163ffffffff1660e01b815260040160206040518083038186803b15801561335357600080fd5b505afa158015613367573d6000803e3d6000fd5b505050506040513d602081101561337d57600080fd5b50516001600160501b03169392505050565b60136020526000908152604090205481565b60116020526000908152604090205481565b6000600260005414156133fb576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b600260009081556001600160a01b0385168152600e602052604090205460ff1661346c576040805162461bcd60e51b815260206004820152601f60248201527f5661756c743a205f746f6b656e496e206e6f742077686974656c697374656400604482015290519081900360640190fd5b6001600160a01b0383166000908152600e602052604090205460ff166134d9576040805162461bcd60e51b815260206004820181905260248201527f5661756c743a205f746f6b656e4f7574206e6f742077686974656c6973746564604482015290519081900360640190fd5b6134e284611309565b6134eb83611309565b60006134f685614ab3565b90506000811161354d576040805162461bcd60e51b815260206004820152601760248201527f5661756c743a20696e76616c696420616d6f756e74496e000000000000000000604482015290519081900360640190fd5b600061355886612f02565b9050600061356586614291565b905060006135778261116286866145e2565b90506135848189896119b5565b6001600160a01b038916600090815260146020526040812054919250906135d5908990849060ff1680156135d057506001600160a01b038b1660009081526014602052604090205460ff165b61512a565b905060006135f46c0c9f2c9cd04674edea4000000061116288886145e2565b6002549091506000906136139083908d906001600160a01b03166119b5565b6002549091506000906136329084908d906001600160a01b03166119b5565b905061363e8c83615334565b6136488b82615048565b6136528c89614dce565b61365c8b86614f2c565b6136678b858c6151f2565b604080516001600160a01b03808f1682528d1660208201528082018a90526060810186905290517ffa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe2359181900360800190a1505060016000555098975050505050505050565b600b5481565b6000816136e1575060006111be565b611a5083836136ef86614291565b61459f565b600f602052600090815260409020546001600160a01b031681565b60085481565b600081613724575060006111be565b611a5083836136ef86612f02565b600b546001600160a01b0382166000908152601b60205260408120549091429161375b9161467d565b11156137695750600061116c565b600b546001600160a01b0383166000908152601b60205260408120549091613796916111629042906146d7565b6001600160a01b038416600090815260176020526040902054909150806137c25760009250505061116c565b6001600160a01b038416600090815260186020526040902054600c546137f3918391611162918691611337916145e2565b949350505050565b600080600061380c898989896121d4565b9092509050600061381d898661467d565b90506000836138355761383082846146d7565b61383f565b61383f828461467d565b905061384f8161116289856145e2565b9b9a5050505050505050505050565b60055481565b6001600160a01b03811660009081526014602052604081205460ff16156138a457506001600160a01b03811660009081526017602052604090205461116c565b6001600160a01b0382166000908152601960205260408120546138c89084906136d2565b6001600160a01b038416600090815260186020908152604080832054601790925290912054919250611168916138ff90849061467d565b906146d7565b60186020526000908152604090205481565b600c5481565b601a6020526000908152604090205481565b60026000541415613975576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b031633146139cc576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6004556001600055565b6000826139e557506000611a50565b6001600160a01b0384166000908152601a6020526040812054613a0890846146d7565b905080613a19576000915050611a50565b6000611a4b620f424061116287856145e2565b60106020526000908152604090205481565b6003546001600160a01b03163314613a90576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6003546001600160a01b03163314613b04576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b60015460ff1615613b5c576040805162461bcd60e51b815260206004820152601a60248201527f5661756c743a20616c726561647920696e697469616c697a6564000000000000604482015290519081900360640190fd5b6001805460ff19168117610100600160a81b0319166101006001600160a01b0397881602179055600280546001600160a01b0319169490951693909317909355600455600791909155600c55565b60026000541415613bf0576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03163314613c47576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6127108111613c9d576040805162461bcd60e51b815260206004820152601b60248201527f5661756c743a20696e76616c6964205f6d61784c657665726167650000000000604482015290519081900360640190fd5b6005556001600055565b6000806000613cb88888888861182b565b9050613cc26159db565b506000818152601c60209081526040808320815160c08101835281548082526001830154948201949094526002820154928101839052600382015460608201526004820154608082015260059091015460a082015292918291613d27918b918b6121d4565b915091506000613d408b856000015186606001516139d6565b9050613d59613d528560000151611452565b829061467d565b905082158015613d6c5750818460200151105b15613dd4578715613dc4576040805162461bcd60e51b815260206004820152601f60248201527f5661756c743a206c6f737365732065786365656420636f6c6c61746572616c00604482015290519081900360640190fd5b600196509450613f409350505050565b602084015183613df0576020850151613ded90846146d7565b90505b81811015613e5c578815613e4b576040805162461bcd60e51b815260206004820152601d60248201527f5661756c743a20666565732065786365656420636f6c6c61746572616c000000604482015290519081900360640190fd5b600197509550613f40945050505050565b600754613e6a90839061467d565b811015613ebf578815613eae5760405162461bcd60e51b8152600401808060200182810382526029815260200180615a806029913960400191505060405180910390fd5b50600196509450613f409350505050565b8451613ecd906127106145e2565b600554613edb9083906145e2565b1015613f34578815613eae576040805162461bcd60e51b815260206004820152601b60248201527f5661756c743a206d61784c657665726167652065786365656465640000000000604482015290519081900360640190fd5b50600096509450505050505b9550959350505050565b601b6020526000908152604090205481565b600e6020526000908152604090205460ff1681565b60026000541415613fb7576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b6002600055613fc78484846147c4565b613fd084611309565b6000613fde8686868661182b565b9050613fe86159db565b506000818152601c6020908152604091829020825160c081018452815480825260018301549382019390935260028201549381019390935260038101546060840152600481015460808401526005015460a0830152614086576040805162461bcd60e51b81526020600482015260156024820152742b30bab63a1d1032b6b83a3c903837b9b4ba34b7b760591b604482015290519081900360640190fd5b600080614097898989896000613ca7565b91509150816140d75760405162461bcd60e51b8152600401808060200182810382526024815260200180615a126024913960400191505060405180910390fd5b6141036140e489836136d2565b6001600160a01b038a166000908152601d60205260409020549061467d565b6001600160a01b0389166000908152601d6020526040902055608083015161412c9089906153b3565b851561414d576020830151835161414d918a91614148916146d7565b614d4f565b7ff83cf4ee624faa7c9173618b67f29216adaf1f37dac2e1890bd5d062fb415282848a8a8a8a886000015189602001518a6080015160405180898152602001886001600160a01b03168152602001876001600160a01b03168152602001866001600160a01b0316815260200185151581526020018481526020018381526020018281526020019850505050505050505060405180910390a16000848152601c602052604081208181556001810182905560028101829055600381018290556004810182905560050155851580156142275750826020015181105b1561425557602083015160009061423e90836146d7565b90506142538961424e8b846136d2565b614dce565b505b61426588611d828a6007546136d2565b61427b886142758a6007546136d2565b876151f2565b5050600160005550505050505050565b60095481565b60006111be8260016127ea565b6001600160a01b038116600090815260126020526040812054806111be5760405162461bcd60e51b8152600401808060200182810382526026815260200180615c4d6026913960400191505060405180910390fd5b60026000541415614339576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03163314614390576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6001600160a01b0381166000908152600e602052604090205460ff166143fd576040805162461bcd60e51b815260206004820152601c60248201527f5661756c743a20746f6b656e206e6f742077686974656c697374656400000000604482015290519081900360640190fd5b6001600160a01b03166000908152600e60209081526040808320805460ff19908116909155600f835281842080546001600160a01b031916905560108352818420849055601183528184208490556012835281842084905560138352818420849055601490925282208054909116905560019055565b60196020526000908152604090205481565b6000600260005414156144cd576040805162461bcd60e51b815260206004820152601f6024820152600080516020615a36833981519152604482015290519081900360640190fd5b60026000556003546001600160a01b03163314614524576040805162461bcd60e51b815260206004820152601060248201526f2b30bab63a1d103337b93134b23232b760811b604482015290519081900360640190fd5b6001600160a01b0383166000908152601d60205260409020548061454c5760009150506127df565b6001600160a01b0384166000908152601d60205260408120556145708482856151f2565b50600160005592915050565b6002546001600160a01b031681565b60015461010090046001600160a01b031681565b6000826145ae57506000611a50565b6001600160a01b0384166000908152601160205260409020546145d98361116286600a85900a6145e2565b95945050505050565b6000826145f1575060006111be565b828202828482816145fe57fe5b0414611a505760405162461bcd60e51b8152600401808060200182810382526021815260200180615aa96021913960400191505060405180910390fd5b6000611a5083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061565a565b600082820183811015611a50576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611a5083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506156fc565b336001600160a01b038216141561472f57611449565b60015461010090046001600160a01b031633141561474c57611449565b6001600160a01b0381166000908152600d6020908152604080832033845290915290205460ff16611449576040805162461bcd60e51b815260206004820152601960248201527f5661756c743a20696e76616c6964206d73672e73656e64657200000000000000604482015290519081900360640190fd5b80156148e457816001600160a01b0316836001600160a01b031614614830576040805162461bcd60e51b815260206004820152601860248201527f5661756c743a206d69736d61746368656420746f6b656e730000000000000000604482015290519081900360640190fd5b6001600160a01b0383166000908152600e602052604090205460ff166148875760405162461bcd60e51b8152600401808060200182810382526027815260200180615b1b6027913960400191505060405180910390fd5b6001600160a01b03831660009081526014602052604090205460ff16156148df5760405162461bcd60e51b8152600401808060200182810382526031815260200180615bd16031913960400191505060405180910390fd5b6149ea565b6001600160a01b0383166000908152600e602052604090205460ff1661493b5760405162461bcd60e51b8152600401808060200182810382526027815260200180615b1b6027913960400191505060405180910390fd5b6001600160a01b03831660009081526014602052604090205460ff166149925760405162461bcd60e51b815260040180806020018281038252602d815260200180615c9a602d913960400191505060405180910390fd5b6001600160a01b03821660009081526014602052604090205460ff16156149ea5760405162461bcd60e51b815260040180806020018281038252602c815260200180615aca602c913960400191505060405180910390fd5b505050565b6000806149fb85611452565b90506000614a0a8786866139d6565b9050614a16828261467d565b91506000614a2488846136d2565b6001600160a01b0389166000908152601d6020526040902054909150614a4a908261467d565b6001600160a01b0389166000818152601d602090815260409182902093909355805191825291810185905280820183905290517f5d0c0019d3d45fadeb74eff9d2c9924d146d000ac6bcf3c28bf0ac3c9baa011a9181900360600190a150909695505050505050565b6001600160a01b03811660008181526015602090815260408083205481516370a0823160e01b8152306004820152915193949093859391926370a08231926024808301939192829003018186803b158015614b0d57600080fd5b505afa158015614b21573d6000803e3d6000fd5b505050506040513d6020811015614b3757600080fd5b50516001600160a01b038516600090815260156020526040902081905590506137f381836146d7565b81614ba7578015614ba25760405162461bcd60e51b8152600401808060200182810382526025815260200180615af66025913960400191505060405180910390fd5b614be6565b80821015614be65760405162461bcd60e51b815260040180806020018281038252602a815260200180615a56602a913960400191505060405180910390fd5b5050565b6001600160a01b038216600090815260186020526040902054614c0d908261467d565b6001600160a01b0383166000908152601860208181526040808420859055601782529092205491521015614c88576040805162461bcd60e51b815260206004820152601b60248201527f5661756c743a2072657365727665206578636565647320706f6f6c0000000000604482015290519081900360640190fd5b604080516001600160a01b03841681526020810183905281517faa5649d82f5462be9d19b0f2b31a59b2259950a6076550bac9f3a1c07db9f66d929181900390910190a15050565b6001600160a01b038216600090815260196020526040902054614cf3908261467d565b6001600160a01b03831660008181526019602090815260409182902093909355805191825291810183905281517fd9d4761f75e0d0103b5cbeab941eeb443d7a56a35b5baf2a0787c03f03f4e474929181900390910190a15050565b6001600160a01b038216600090815260196020526040902054614d7290826146d7565b6001600160a01b03831660008181526019602090815260409182902093909355805191825291810183905281517f34e07158b9db50df5613e591c44ea2ebc82834eff4a4dc3a46e000e608261d68929181900390910190a15050565b6001600160a01b038216600090815260176020526040902054614df1908261467d565b6001600160a01b03831660008181526017602090815260408083209490945583516370a0823160e01b8152306004820152935191936370a082319260248083019392829003018186803b158015614e4757600080fd5b505afa158015614e5b573d6000803e3d6000fd5b505050506040513d6020811015614e7157600080fd5b50516001600160a01b038416600090815260176020526040902054909150811015614ee3576040805162461bcd60e51b815260206004820152601760248201527f5661756c743a20696e76616c696420696e637265617365000000000000000000604482015290519081900360640190fd5b604080516001600160a01b03851681526020810184905281517f976177fbe09a15e5e43f848844963a42b41ef919ef17ff21a17a5421de8f4737929181900390910190a1505050565b604080518082018252601a81527f5661756c743a20706f6f6c416d6f756e742065786365656465640000000000006020808301919091526001600160a01b038516600090815260179091529190912054614f879183906156fc565b6001600160a01b038316600090815260176020908152604080832084905560189091529020541115615000576040805162461bcd60e51b815260206004820152601b60248201527f5661756c743a2072657365727665206578636565647320706f6f6c0000000000604482015290519081900360640190fd5b604080516001600160a01b03841681526020810183905281517f112726233fbeaeed0f5b1dba5cb0b2b81883dee49fb35ff99fd98ed9f6d31eb0929181900390910190a15050565b6001600160a01b0382166000908152601660205260409020548181116150c3576001600160a01b0383166000818152601660209081526040808320929092558151928352820183905280517fe1e812596aac93a06ecc4ca627014d18e30f5c33b825160cc9d5c0ba61e452279281900390910190a150614be6565b6150cd81836146d7565b6001600160a01b03841660008181526016602090815260409182902093909355805191825291810184905281517fe1e812596aac93a06ecc4ca627014d18e30f5c33b825160cc9d5c0ba61e45227929181900390910190a1505050565b6000808261513a5760085461513e565b6009545b9050600061515c61271061116261515582866146d7565b88906145e2565b9050600061516a86836146d7565b6001600160a01b0388166000908152601d6020526040902054909150615190908261467d565b6001600160a01b0388166000818152601d602090815260409182902093909355805191825291810183905281517fd95db0530068098b3fdcc347b751a6a2a5cc8492a858255b1d4ff87c920b3d3d929181900390910190a15095945050505050565b6152066001600160a01b0384168284615756565b604080516370a0823160e01b815230600482015290516001600160a01b038516916370a08231916024808301926020929190829003018186803b15801561524c57600080fd5b505afa158015615260573d6000803e3d6000fd5b505050506040513d602081101561527657600080fd5b50516001600160a01b039093166000908152601560205260409020929092555050565b6000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156152e857600080fd5b505afa1580156152fc573d6000803e3d6000fd5b505050506040513d602081101561531257600080fd5b50516001600160a01b0390921660009081526015602052604090209190915550565b6001600160a01b038216600090815260166020526040902054615357908261467d565b6001600160a01b03831660008181526016602090815260409182902093909355805191825291810183905281517f64243679a443432e2293343b77d411ff6144370404618f00ca0d2025d9ca9882929181900390910190a15050565b604080518082018252601b81527f5661756c743a20696e73756666696369656e74207265736572766500000000006020808301919091526001600160a01b03851660009081526018909152919091205461540e9183906156fc565b6001600160a01b03831660008181526018602090815260409182902093909355805191825291810183905281517f533cb5ed32be6a90284e96b5747a1bfc2d38fdb5768a6b5f67ff7d62144ed67b929181900390910190a15050565b600080600061547b8989898761182b565b6000818152601c602052604081208054600382015493945090926154a3918c918a91906149ef565b90506000806000806154bf8d876000015488600201548d6121d4565b875491955085935091506154d7906111628d846145e2565b9250505060008280156154ea5750600082115b1561551a575060058401805482019055808861551a57600061550c8e846136d2565b90506155188e82614f2c565b505b821580156155285750600082115b1561556c57600185015461553c90836146d7565b6001860155886155605760006155528e846136d2565b905061555e8e82614dce565b505b60058501805483900390555b8a156155945761557c818c61467d565b600186015490915061558e908c6146d7565b60018601555b84548a14156155b75760018501546155ad90829061467d565b6000600187015590505b80848111156155d1576155ca82866146d7565b9050615605565b60018601546155e090866146d7565b600187015589156156055760006155f78f876136d2565b90506156038f82614f2c565b505b60408051888152851515602082015280820185905290517f3ff41bdde87755b687ae83d0221a232b6be51a803330ed9661c1b5d0105e0d8a9181900360600190a1909e909d509b505050505050505050505050565b600081836156e65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156156ab578181015183820152602001615693565b50505050905090810190601f1680156156d85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816156f257fe5b0495945050505050565b6000818484111561574e5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156156ab578181015183820152602001615693565b505050900390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526149ea90849060606157f8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166158549092919063ffffffff16565b8051909150156149ea5780806020019051602081101561581757600080fd5b50516149ea5760405162461bcd60e51b815260040180806020018281038252602a815260200180615c23602a913960400191505060405180910390fd5b60606137f38484600085856158688561596f565b6158b9576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106158f85780518252601f1990920191602091820191016158d9565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461595a576040519150601f19603f3d011682016040523d82523d6000602084013e61595f565b606091505b5091509150612041828286615975565b3b151590565b60608315615984575081611a50565b8251156159945782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156156ab578181015183820152602001615693565b6040518060c00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152509056fe5661756c743a20706f736974696f6e2063616e6e6f74206265206c6971756964617465645265656e7472616e637947756172643a207265656e7472616e742063616c6c005661756c743a205f73697a65206d757374206265206d6f7265207468616e205f636f6c6c61746572616c5661756c743a206c69717569646174696f6e20666565732065786365656420636f6c6c61746572616c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775661756c743a205f696e646578546f6b656e206d757374206e6f74206265206120737461626c65546f6b656e5661756c743a20636f6c6c61746572616c2073686f756c642062652077697468647261776e5661756c743a205f636f6c6c61746572616c546f6b656e206e6f742077686974656c69737465645661756c743a20696e76616c6964205f737761704665654261736973506f696e74735661756c743a20696e76616c6964205f66756e64696e6752617465466163746f725661756c743a20696e76616c6964205f737461626c65537761704665654261736973506f696e74735661756c743a20696e76616c6964205f6d617267696e4665654261736973506f696e74735661756c743a205f636f6c6c61746572616c546f6b656e206d757374206e6f74206265206120737461626c65546f6b656e5661756c743a20696e76616c6964205f6c69717569646174696f6e4665655573645361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645661756c743a20696e76616c696420726564656d7074696f6e20626173697320706f696e74735661756c743a20696e73756666696369656e7420636f6c6c61746572616c20666f7220666565735661756c743a205f636f6c6c61746572616c546f6b656e206d757374206265206120737461626c65546f6b656ea264697066735822122064f36adbcba1d795ea2f6b917583f574c30557980d0d886f3640404f4d481df764736f6c634300060c0033

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