S Price: $0.068146 (+1.49%)
Gas: 55 Gwei

Contract

0xb6c3E2bC6B90f1DD91DAD3244D2393368748F964

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
_become530501012025-11-01 20:46:3685 days ago1762029996IN
0xb6c3E2bC...68748F964
0 S0.00181250.0001

View more zero value Internal Transactions in Advanced View mode

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

Contract Source Code Verified (Exact Match)

Contract Name:
TradingFloorV1

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 26 : TradingFloorV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../interfaces/ITradingFloorV1.sol";
import "../interfaces/IRegistryV1.sol";
import "../interfaces/ILexPoolV1.sol";
import "../interfaces/IPoolAccountantV1.sol";
import {ILynxVersionedContract} from "../interfaces/ILynxVersionedContract.sol";

import "./TradingFloorStorage.sol";
import "./TradingFloorProxy.sol";

/**
 * @title TradingFloorV1
 * @notice The TradingFloor contract is the main contract for the Lynx trading platform.
 * It handles the opening, updating and closing of positions.
 *
 * @dev Version History:
 * - v1.00 (1000): Initial version with core trading functionality
 *   - Per-pair trader tracking using pairTraders and pairTradersInfo mappings
 *   - Basic position management with maxTradesPerPair limit
 *   - Standard fee collection and position lifecycle management
 *
 * - v1.01 (1010): Global trader tracking system implementation
 *   - Replaced per-pair trader tracking with global trader array
 *   - Added `traders` array for all active traders across all pairs
 *   - Added `tradersIndex` mapping with 1-based indexing (0 = not in array)
 *   - Added `activePositionIdsByTrader` for global position tracking
 *   - Added `positionIdToActivePositionIndex` for O(1) position removal
 *   - Changed `maxTradesPerPair` to `maxTradesPerTrader` for global limits
 *   - Implemented swap-and-pop pattern for efficient trader removal
 *   - Deprecated old mappings: `pairTraders` → `deprecated_pairTraders`,
 *     `pairTradersInfo` → `deprecated_pairTradersInfo`
 *   - Benefits: Better gas efficiency, simplified cross-pair management, O(1) operations
 *
 * - v1.01.1 (1011): Limits update
 *   - Modified SL/TP update validation to check against current price instead of open price
 *
 * - v1.01.2 (1012): Bug fixes
 *   - Fixed issue with trader removal when not present in traders array
 *
 * - v1.01.3 (1013): Trader tracking consistency fix
 *   - Added IncorrectTraderIndex event for tracking discrepancies
 *   - Enhanced decreaseOrRemoveFromTradersLists to handle corrupted tradersIndex mapping
 *   - Prevents incorrect trader removal when index points to wrong address
 *   - Cleans up stale mappings allowing natural self-healing on next position open
 *
 * - v1.01.4 (1014): Trust Triggers SL execution price
 *   - Changed closeExistingPosition_Limit to use effectivePrice instead of positionLimitInfo.sl for SL triggers
 *   - Enables TriggersV1 to calculate buffered execution price when market gaps through SL
 *   - Validation still ensures effectivePrice is on correct side of SL (security maintained)
 */
contract TradingFloorV1 is
  TradingFloorV1Storage,
  ITradingFloorV1Functionality,
  ILynxVersionedContract,
  LexErrors
{
  using SafeERC20 for IERC20;

  // ***** Constants (ILynxVersionedContract interface) *****

  string public constant CONTRACT_NAME = "TradingFloorV1";
  string public constant CONTRACT_VERSION = "1014"; // 1.01.4 - Trust Triggers SL execution price

  // ***** Constants *****

  uint public constant MAX_FEE_FRACTION_FOR_CANCEL = FRACTION_SCALE / 100; // FRACTION_SCALE

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

  event SettlementAssetAdded(
    address indexed asset,
    address indexed lexPool,
    address indexed poolAccountant
  );

  event NumberUpdated(string indexed name, uint value);
  event PairPausedChange(uint indexed pairId, bool indexed isPaused);

  event PositionIdentifiersStored(
    bytes32 indexed positionId,
    PositionIdentifiers identifiers
  );

  // Old event, left for indexing purposes
  event PendingPositionStored(
    bytes32 indexed positionId,
    PositionPhase phase,
    PositionRequestIdentifiers_Old requestIdentifiers,
    PositionRequestParams requestParams,
    uint32 _spreadReductionF
  );
  event PendingPositionStoredV1010(
    bytes32 indexed positionId,
    PositionPhase phase,
    uint32 index,
    PositionRequestIdentifiers requestIdentifiers,
    PositionRequestParams requestParams,
    uint32 _spreadReductionF
  );

  event PositionOpenCancelledByMarketPriceRange(
    bytes32 indexed positionId,
    uint64 triggerPrice
  );

  event PositionOpenCancelledByCap(
    bytes32 indexed positionId,
    CapType capType,
    uint256 value
  );

  event PositionOpened(
    bytes32 indexed positionId,
    uint64 openPrice,
    uint64 tp,
    uint64 sl,
    uint totalOpenFee,
    uint lexFeePart
  );

  event PositionSetForMarketClose(
    bytes32 indexed positionId,
    uint64 _minPrice,
    uint64 _maxPrice
  );

  event PositionClosedMarket(
    bytes32 indexed positionId,
    uint triggerPrice,
    uint tradeValue,
    int profitPrecision
  );
  event PositionClosedLimit(
    bytes32 indexed positionId,
    LimitTrigger indexed limitTrigger,
    uint triggerPrice,
    uint effectiveClosePrice,
    uint tradeValue,
    int profitPrecision
  );

  event FeeRegistered(
    bytes32 indexed positionId,
    address indexed token,
    FeeType indexed feeType,
    uint amount
  );

  event FeeCollected(
    address indexed token,
    FeeType indexed feeType,
    address indexed receiver,
    uint amount
  );

  event PendingPositionCancelled(
    bytes32 indexed positionId,
    address indexed source,
    uint fee
  );
  event PositionMarketCloseCancelled(
    bytes32 indexed positionId,
    address indexed source,
    uint fee
  );

  event PendingPositionUpdated(
    bytes32 indexed positionId,
    uint64 tp,
    uint64 sl,
    uint64 minPrice,
    uint64 maxPrice
  );

  event OpenedPositionUpdated(
    bytes32 indexed positionId,
    uint16 indexed pairId,
    bool buy,
    PositionField indexed updatedField,
    uint64 fieldValue
  );

  event IncorrectTraderIndex(
    address indexed trader,
    uint256 traderIndex,
    address foundTraderAddress
  );

  // ***** Modifiers *****

  modifier onlyTradersPortal() {
    require(
      IRegistryV1(registry).isTradersPortalAndLocker(msg.sender),
      "!TradersPortal"
    );
    _;
  }
  modifier onlyTriggers() {
    require(IRegistryV1(registry).isTriggersAndLocker(msg.sender), "!Triggers");
    _;
  }
  modifier onlyTradersPortalOrTriggers() {
    require(
      IRegistryV1(registry).isTradersPortalOrTriggersAndLocker(msg.sender),
      "!(TradersPortal||Triggers)"
    );
    _;
  }

  // ***** Views (ILynxVersionedContract interface) *****

  function getContractName() external pure override returns (string memory) {
    return CONTRACT_NAME;
  }

  function getContractVersion() external pure override returns (string memory) {
    return CONTRACT_VERSION;
  }

  // ***** Views *****

  /**
   * Generates the hash used to identify a position
   */
  function generatePositionHashId(
    address settlementAsset,
    address trader,
    uint16 pairId,
    uint32 index
  ) public pure returns (bytes32 hashId) {
    hashId = keccak256(
      abi.encodePacked(settlementAsset, trader, pairId, index)
    );
  }

  /**
   * Builds the structs with info needed fo 'Triggers' interactions
   */
  function getPositionTriggerInfo(
    bytes32 _positionId
  )
    external
    view
    returns (
      PositionPhase positionPhase,
      uint64 timestamp,
      uint16 pairId,
      bool long,
      uint32 spreadReductionF
    )
  {
    return (
      positionsById[_positionId].phase,
      positionsById[_positionId].inPhaseSince,
      positionIdentifiersById[_positionId].pairId,
      positionsById[_positionId].long,
      positionsById[_positionId].spreadReductionF
    );
  }

  /**
   * Builds the structs with info needed for 'TradersPortal' interactions
   */
  function getPositionPortalInfo(
    bytes32 _positionId
  )
    external
    view
    returns (PositionPhase positionPhase, uint64 timestamp, address trader)
  {
    return (
      positionsById[_positionId].phase,
      positionsById[_positionId].inPhaseSince,
      positionIdentifiersById[_positionId].trader
    );
  }

  /**
   * Builds the structs with info needed for 'PoolAccountnat' interactions
   */
  function getPositionRegistrationParams(
    bytes32 _positionId
  )
    public
    view
    returns (
      PoolAccountantStructs.PositionRegistrationParams memory registrationParams
    )
  {
    Position memory position = positionsById[_positionId];

    registrationParams.collateral = position.collateral;
    registrationParams.leverage = position.leverage;
    registrationParams.openPrice = position.openPrice;
    registrationParams.long = position.long;
    registrationParams.tp = positionLimitsInfoById[_positionId].tp;

    return registrationParams;
  }

  /**
   * @return true if the given asset has a Lex defined for it
   */
  function isSettlementAssetSupported(
    address settlementAsset
  ) public view returns (bool) {
    return lexPoolForAsset[settlementAsset] != address(0);
  }

  function deprecated_pairTradersArray(
    address _asset,
    uint _pairIndex
  ) external view returns (address[] memory) {
    return deprecated_pairTraders[_asset][_pairIndex];
  }

  /**
   * @notice Returns the length of the global traders array
   * @dev Part of the v1.01 global trader tracking system
   * @return Number of traders with at least one active position
   */
  function tradersAmount() external view returns (uint256) {
    return traders.length;
  }

  /**
   * @notice Gets the next position index for a trader to use in position ID generation
   * @dev Part of the v1.01 global tracking system. Indices start at 11 to avoid
   *      collision with legacy positions. This ensures unique position IDs across
   *      all pairs for a given trader.
   * @param _trader The trader address
   * @return The next available position index for this trader
   */
  function getNextPositionIndexForTrader(
    address _trader
  ) public view returns (uint32) {
    uint32 lastUsedIndex = pairTradersLastUsedPositionIndex[_trader];
    require(lastUsedIndex < type(uint32).max, "POSITION_INDEX_OVERFLOW");

    // If this is the first position for this trader,
    // start from index 11 to avoid collision with existing positions
    if (lastUsedIndex < 11) {
      return 11;
    }

    return lastUsedIndex + 1;
  }

  /**
   * @notice Returns all active position IDs for a trader across ALL pairs
   * @dev Part of the v1.01 global tracking system. This replaces the old per-pair
   *      position tracking with a unified view of all trader positions.
   * @param _trader The trader address
   * @return Array of active position IDs across all trading pairs
   */
  function getActivePositionIdsForTrader(
    address _trader
  ) external view returns (bytes32[] memory) {
    return activePositionIdsByTrader[_trader];
  }

  function getActivePositionsAmountForTrader(
    address _trader
  ) external view returns (uint256) {
    return activePositionIdsByTrader[_trader].length;
  }

  // ***** Initialization functions *****

  /**
   * @notice Part of the Proxy mechanism
   */
  function _become(TradingFloorProxy tradingFloorProxy) public {
    require(msg.sender == tradingFloorProxy.admin(), "!proxy.admin");
    require(tradingFloorProxy._acceptImplementation() == 0, "fail");
  }

  // ***** Registry Functions *****

  /**
   * Adds a new settlement asset to the trading floor with the given LexPool and PoolAccountant
   * @dev This function is only callable by the registry
   */
  function supportNewSettlementAsset(
    address _asset,
    address _lexPool,
    address _poolAccountant
  ) external {
    require(msg.sender == registry, "!Registry");

    require(lexPoolForAsset[_asset] == address(0), "ASSET_ALREADY_SUPPORTED");

    // Store addresses
    lexPoolForAsset[_asset] = _lexPool;
    poolAccountantForAsset[_asset] = _poolAccountant;

    emit SettlementAssetAdded(_asset, _lexPool, _poolAccountant);
  }

  // ***** Admin Functions *****

  /**
   * Setter for numeric parameters
   */
  function setTradeParam(
    AdminNumericParam numericParam,
    uint value
  ) external onlyAdmin {
    require(value > 0, "CANNOT_BE_ZERO");
    string memory name;

    if (numericParam == AdminNumericParam.MAX_TRADES_PER_TRADER) {
      name = "maxTradesPerTrader";
      maxTradesPerTrader = value;
    } else if (numericParam == AdminNumericParam.MAX_SL_F) {
      // Note: Forcing a value of 50% or above
      require(value >= (FRACTION_SCALE * 50) / 100, "TRADE_PARAM_RESTRICTION");
      name = "maxSlF";
      maxSlF = value;
    } else if (numericParam == AdminNumericParam.MAX_SANITY_PROFIT_F) {
      // Note : Forcing a value of 200% or above
      require(value >= 2 * FRACTION_SCALE, "TRADE_PARAM_RESTRICTION");
      name = "maxSanityProfitF";
      maxSanityProfitF = value;
    } else {
      revert("UNSUPPORTED");
    }

    emit NumberUpdated(name, value);
  }

  /**
   * Allows to pause/unpause the opening/updating of positions in the given pair
   */
  function setPairPaused(uint _pairId, bool _isPaused) external onlyAdmin {
    pausedPairs[_pairId] = _isPaused;
    emit PairPausedChange(_pairId, _isPaused);
  }

  // ***** Traders Portal Interaction *****

  /**
   * This function stores the request for opening a new Position
   * @return positionId The id of the new position (pending to be opened)
   */
  function storePendingPosition(
    OpenOrderType _orderType,
    PositionRequestIdentifiers memory _requestIdentifiers,
    PositionRequestParams memory _requestParams,
    uint32 _spreadReductionF
  ) external override onlyTradersPortal returns (bytes32 positionId) {
    require(
      isSettlementAssetSupported(_requestIdentifiers.settlementAsset),
      "NON_SUPPORTED_SETTLEMENT_ASSET"
    );
    require(!pausedPairs[_requestIdentifiers.pairId], "PAIR_PAUSED");

    require(
      _orderType == OpenOrderType.MARKET || _orderType == OpenOrderType.LIMIT,
      "UNSUPPORTED_ORDER_TYPE"
    );

    requireValidOpenTradeParameters(
      _requestParams.long,
      _requestParams.minPrice,
      _requestParams.maxPrice,
      _requestParams.tp,
      _requestParams.sl
    );

    require(
      activePositionIdsByTrader[_requestIdentifiers.trader].length <
        maxTradesPerTrader,
      "MAX_TRADES_PER_TRADER"
    );

    uint32 index;
    (positionId, index) = storeIdentifiersIfNeeded(
      _requestIdentifiers.settlementAsset,
      _requestIdentifiers.trader,
      _requestIdentifiers.pairId
    );

    takeSettlement(
      _requestIdentifiers.settlementAsset,
      _requestIdentifiers.trader,
      _requestParams.collateral
    );

    // Add/Increase in traders
    increaseOrAddToTradersLists(_requestIdentifiers.trader);

    Position storage position = positionsById[positionId];
    require(position.collateral == 0, "ID_USED");

    position.spreadReductionF = _spreadReductionF;

    position.long = _requestParams.long;
    position.leverage = _requestParams.leverage;
    position.collateral = _requestParams.collateral;

    PositionPhase phase = _orderType == OpenOrderType.MARKET
      ? PositionPhase.OPEN_MARKET
      : PositionPhase.OPEN_LIMIT;
    position.phase = phase;
    position.inPhaseSince = uint64(block.timestamp);

    PositionLimitsInfo storage positionLimitInfo = positionLimitsInfoById[
      positionId
    ];

    positionLimitInfo.tp = _requestParams.tp;
    positionLimitInfo.sl = _requestParams.sl;

    PositionTriggerPrices storage triggerPrices = triggerPricesById[positionId];
    triggerPrices.minPrice = _requestParams.minPrice;
    triggerPrices.maxPrice = _requestParams.maxPrice;
    triggerPrices.tpByFraction = _requestParams.tpByFraction;
    triggerPrices.slByFraction = _requestParams.slByFraction;

    emit PendingPositionStoredV1010(
      positionId,
      phase,
      index,
      _requestIdentifiers,
      _requestParams,
      _spreadReductionF
    );
  }

  /**
   * Sets the given position to be market closed
   */
  function setOpenedPositionToMarketClose(
    bytes32 _positionId,
    uint64 _minPrice,
    uint64 _maxPrice
  ) external override onlyTradersPortal {
    // note : using 'storage' to reduce gas cost and contract size
    Position storage position = positionsById[_positionId];
    require(position.collateral > 0, "NO_SUCH_POSITION");

    require(position.phase == PositionPhase.OPENED, "WRONG_PHASE");
    position.phase = PositionPhase.CLOSE_MARKET;
    position.inPhaseSince = uint64(block.timestamp);

    PositionTriggerPrices storage triggerPrices = triggerPricesById[
      _positionId
    ];
    triggerPrices.minPrice = _minPrice;
    triggerPrices.maxPrice = _maxPrice;

    emit PositionSetForMarketClose(_positionId, _minPrice, _maxPrice);
  }

  /**
   * Updates one of the fields in a pending LIMIT_OPEN position
   */
  function updatePendingPosition_openLimit(
    bytes32 _positionId,
    uint64 _minPrice,
    uint64 _maxPrice,
    uint64 _tp,
    uint64 _sl
  ) external override onlyTradersPortal {
    Position storage _position = positionsById[_positionId];

    require(_position.phase == PositionPhase.OPEN_LIMIT, "WRONG_PHASE");
    require(
      !pausedPairs[positionIdentifiersById[_positionId].pairId],
      "PAIR_PAUSED"
    );

    requireValidOpenTradeParameters(
      _position.long,
      _minPrice,
      _maxPrice,
      _tp,
      _sl
    );

    // Update the pending position timestamp
    _position.inPhaseSince = uint64(block.timestamp);

    // Update the position locally
    PositionLimitsInfo storage _positionLimitInfo = positionLimitsInfoById[
      _positionId
    ];
    _positionLimitInfo.tp = _tp;
    _positionLimitInfo.sl = _sl;
    // Note : Not updating the timestamps as they only need to be updated for Opened positions

    PositionTriggerPrices storage triggerPrices = triggerPricesById[
      _positionId
    ];
    triggerPrices.minPrice = _minPrice;
    triggerPrices.maxPrice = _maxPrice;

    emit PendingPositionUpdated(_positionId, _tp, _sl, _minPrice, _maxPrice);
  }

  // ***** Triggers Interaction *****

  /**
   * Called by the triggers in order to Open a new position by market price
   */
  function openNewPosition_market(
    bytes32 _positionId,
    uint64 assetEffectivePrice,
    uint256 feeForCancellation
  ) external onlyTriggers {
    openNewTradeInternal(
      _positionId,
      PositionPhase.OPEN_MARKET,
      assetEffectivePrice,
      feeForCancellation
    );
  }

  /**
   * Called by the triggers in order to Open a new position by reached limit
   */
  function openNewPosition_limit(
    bytes32 _positionId,
    uint64 assetEffectivePrice,
    uint256 feeForCancellation
  ) external onlyTriggers {
    openNewTradeInternal(
      _positionId,
      PositionPhase.OPEN_LIMIT,
      assetEffectivePrice,
      feeForCancellation
    );
  }

  /**
   * Called by the triggers in order to Close an existing position by market price
   */
  function closeExistingPosition_Market(
    bytes32 _positionId,
    uint64, // assetPrice
    uint64 effectivePrice
  ) external override onlyTriggers {
    PositionTriggerPrices memory triggerPrices = triggerPricesById[_positionId];
    require(triggerPrices.maxPrice > 0, "NO_SUCH_POSITION");

    if (
      triggerPrices.minPrice > effectivePrice ||
      triggerPrices.maxPrice < effectivePrice
    ) {
      cancelMarketCloseForPositionInternal(
        address(this),
        _positionId,
        CloseOrderType.MARKET
      );
    } else {
      (
        uint tradeValue,
        int profitPrecision,
        uint finalClosingPrice
      ) = closeExistingTradeInternal(
          _positionId,
          effectivePrice,
          PositionCloseType.MARKET
        );

      emit PositionClosedMarket(
        _positionId,
        finalClosingPrice,
        tradeValue,
        profitPrecision
      );
    }
  }

  /**
   * Called by the triggers in order to Close an existing position by a reached limit value
   */
  function closeExistingPosition_Limit(
    bytes32 _positionId,
    LimitTrigger limitTrigger,
    uint64, // assetPrice
    uint64 effectivePrice
  ) external override onlyTriggers {
    Position memory position = positionsById[_positionId];
    require(position.collateral > 0, "NO_SUCH_POSITION");

    PositionLimitsInfo memory positionLimitInfo = positionLimitsInfoById[
      _positionId
    ];

    bool triggerValid = false;
    uint effectiveClosingPrice;
    PositionCloseType positionCloseType;

    if (limitTrigger == LimitTrigger.SL) {
      triggerValid = position.long
        ? effectivePrice <= positionLimitInfo.sl
        : effectivePrice >= positionLimitInfo.sl;
      effectiveClosingPrice = effectivePrice; // Trust Triggers SL execution price (with buffer)
      positionCloseType = PositionCloseType.SL;
    } else if (limitTrigger == LimitTrigger.TP) {
      triggerValid = position.long
        ? effectivePrice >= positionLimitInfo.tp
        : effectivePrice <= positionLimitInfo.tp;
      effectiveClosingPrice = positionLimitInfo.tp;
      positionCloseType = PositionCloseType.TP;
    } else if (limitTrigger == LimitTrigger.LIQ) {
      // Note : The Accountant will be the one to adjust the price for liquidation
      triggerValid = true;
      effectiveClosingPrice = effectivePrice;
      positionCloseType = PositionCloseType.LIQ;
    } else {
      revert("WRONG_LIMIT_TRIGGER");
    }

    // Revert if the conditions are not met for triggering
    require(triggerValid, "FALSE_TRIGGER");

    (
      uint tradeValue,
      int profitPrecision,
      uint finalClosingPrice
    ) = closeExistingTradeInternal(
        _positionId,
        effectiveClosingPrice,
        positionCloseType
      );

    // Checking again for liq to allow quicker failure in TP and SL
    if (positionCloseType == PositionCloseType.LIQ) {
      triggerValid = position.long
        ? effectivePrice <= finalClosingPrice
        : effectivePrice >= finalClosingPrice;
      require(triggerValid, "FALSE_TRIGGER");
    }

    emit PositionClosedLimit(
      _positionId,
      limitTrigger,
      effectivePrice,
      finalClosingPrice,
      tradeValue,
      profitPrecision
    );
  }

  /**
   * Updates a PositionField of an OPEN position
   */
  function updateOpenedPosition(
    bytes32 positionId,
    PositionField updateField,
    uint64 fieldValue,
    uint64 effectivePrice
  ) external onlyTriggers {
    Position storage p = positionsById[positionId];
    PositionLimitsInfo storage limitInfo = positionLimitsInfoById[positionId];
    PositionIdentifiers memory identifiers = positionIdentifiersById[
      positionId
    ];

    require(p.collateral > 0, "NO_SUCH_POSITION");
    require(p.phase == PositionPhase.OPENED, "WRONG_PHASE");

    IPoolAccountantV1 poolAccountant = IPoolAccountantV1(
      poolAccountantForAsset[identifiers.settlementAsset]
    );

    uint64 tpToUse;
    uint64 slToUse;

    if (updateField == PositionField.TP) {
      uint64 correctedTp = correctTp(
        uint64(poolAccountant.maxGainF()),
        p.openPrice,
        p.leverage,
        fieldValue,
        p.long
      );

      // Sanity
      require(correctedTp == fieldValue, "BAD_FIELD_VALUE");
      require(correctedTp != limitInfo.tp, "SAME_TP");
      tpToUse = correctedTp;
      slToUse = limitInfo.sl;
      limitInfo.tpLastUpdated = uint64(block.timestamp);

      // Register the change in the LexPool
      // Might revert if a cap is reached
      poolAccountant.registerUpdateTp(
        positionId,
        identifiers.trader,
        identifiers.pairId,
        p.collateral,
        p.leverage,
        p.long,
        p.openPrice,
        limitInfo.tp,
        tpToUse
      );
    } else if (updateField == PositionField.SL) {
      uint64 correctedSl = correctSl(
        uint64(poolAccountant.maxGainF()),
        p.openPrice,
        p.leverage,
        fieldValue,
        p.long
      );

      // Sanity
      require(correctedSl == fieldValue, "BAD_FIELD_VALUE");
      require(correctedSl != limitInfo.sl, "SAME_SL");

      tpToUse = limitInfo.tp;
      slToUse = correctedSl;
      limitInfo.slLastUpdated = uint64(block.timestamp);
    } else {
      revert("UNSUPPORTED");
    }

    // Ensure the new params are valid
    requireValidOpenTradeParameters(
      p.long,
      effectivePrice,
      effectivePrice,
      tpToUse,
      slToUse
    );

    limitInfo.sl = slToUse;
    limitInfo.tp = tpToUse;

    emit OpenedPositionUpdated(
      positionId,
      identifiers.pairId,
      p.long,
      updateField,
      fieldValue
    );
  }

  // ***** Traders Portal/Triggers Shared Interaction *****

  /**
   * Cancel a pending open position, returning assets to trader.
   */
  function cancelPendingPosition(
    bytes32 _positionId,
    OpenOrderType _orderType,
    uint feeFraction
  ) external override onlyTradersPortalOrTriggers {
    require(feeFraction <= MAX_FEE_FRACTION_FOR_CANCEL, "FEE_FRACTION_TOO_BIG");

    Position memory position = positionsById[_positionId];
    require(positionsById[_positionId].collateral > 0, "NO_SUCH_POSITION");
    PositionIdentifiers memory identifiers = positionIdentifiersById[
      _positionId
    ];

    if (_orderType == OpenOrderType.MARKET) {
      require(position.phase == PositionPhase.OPEN_MARKET, "NOT_MARKET_ORDER");
    } else if (_orderType == OpenOrderType.LIMIT) {
      require(position.phase == PositionPhase.OPEN_LIMIT, "NOT_LIMIT_ORDER");
    } else {
      revert("WRONG_ORDER_TYPE");
    }

    settleCanceledOpenOrderInternal(
      _positionId,
      identifiers.settlementAsset,
      identifiers.trader,
      position.collateral,
      position.leverage,
      feeFraction,
      msg.sender
    );
  }

  /**
   * Cancel a CLOSE_MARKET position, returning the position to an OPEN phase.
   * @dev Currently no fee is being taken for this action
   */
  function cancelMarketCloseForPosition(
    bytes32 _positionId,
    CloseOrderType _orderType,
    uint // feeFraction
  ) external override onlyTradersPortalOrTriggers {
    cancelMarketCloseForPositionInternal(msg.sender, _positionId, _orderType);
  }

  /**
   * Handles the cancellation of a "market close" order
   */
  function cancelMarketCloseForPositionInternal(
    address source,
    bytes32 _positionId,
    CloseOrderType _orderType
  ) internal {
    require(positionsById[_positionId].collateral > 0, "NO_SUCH_POSITION");

    delete triggerPricesById[_positionId];

    if (_orderType == CloseOrderType.MARKET) {
      require(
        positionsById[_positionId].phase == PositionPhase.CLOSE_MARKET,
        "WRONG_PHASE"
      );
    } else {
      revert("WRONG_ORDER_TYPE");
    }

    positionsById[_positionId].phase = PositionPhase.OPENED;
    positionsById[_positionId].inPhaseSince = uint64(block.timestamp);

    emit PositionMarketCloseCancelled(_positionId, source, 0);
  }

  // ***** Fees Manager Interaction *****

  /**
   * Sends all fee accrued in the SA+feeType to the '_to' address
   * @dev Allows a dynamic and flexible way to direct fees.
   */
  function collectFee(address _asset, FeeType _feeType, address _to) external {
    require(
      msg.sender == IRegistryV1(registry).feesManagers(_asset),
      "!FeesManager"
    );
    collectFeeInternal(_asset, _feeType, _to);
  }

  // ***** Internal Position Open/Close logic *****

  /**
   * Stores the identifying values of the position.
   * @dev Saves gas after the first time a SA-trader-pair-index position was registered in this contract
   * @return positionId The position id that matched these identifiers
   */
  function storeIdentifiersIfNeeded(
    address settlementAsset,
    address trader,
    uint16 pairId
  ) internal returns (bytes32 positionId, uint32 index) {
    index = getNextPositionIndexForTrader(trader);

    positionId = generatePositionHashId(settlementAsset, trader, pairId, index);

    PositionIdentifiers storage identifiers = positionIdentifiersById[
      positionId
    ];

    // Store the identifier once
    if (identifiers.index == 0) {
      identifiers.settlementAsset = settlementAsset;
      identifiers.trader = trader;
      identifiers.pairId = pairId;
      identifiers.index = index;

      // Update lastUsedPositionIndex
      pairTradersLastUsedPositionIndex[trader] = index;

      // Add to active position IDs tracking
      addToActivePositionIds(trader, positionId);

      emit PositionIdentifiersStored(positionId, identifiers);
    }
  }

  /**
   * Handles verifications and logic for the opening of a new position.
   * @dev This function will "swallow" the "CapError" custom error that can be thrown by the 'PoolAccountant' contract
   *      and in such case will proceed to cancel the open order.
   */
  function openNewTradeInternal(
    bytes32 _positionId,
    PositionPhase _expectedPhase,
    uint64 assetEffectivePrice,
    uint256 feeForCancellation
  ) internal {
    PositionTriggerPrices memory triggerPrices = triggerPricesById[_positionId];

    Position memory _position = positionsById[_positionId];
    require(_position.collateral > 0, "NO_SUCH_POSITION");
    PositionIdentifiers memory identifiers = positionIdentifiersById[
      _positionId
    ];
    require(!pausedPairs[identifiers.pairId], "PAIR_PAUSED");

    require(_position.phase == _expectedPhase, "WRONG_PHASE");

    if (_expectedPhase == PositionPhase.OPEN_MARKET) {
      if (
        triggerPrices.minPrice > assetEffectivePrice ||
        triggerPrices.maxPrice < assetEffectivePrice
      ) {
        emit PositionOpenCancelledByMarketPriceRange(
          _positionId,
          assetEffectivePrice
        );
        settleCanceledOpenOrderInternal(
          _positionId,
          identifiers.settlementAsset,
          identifiers.trader,
          _position.collateral,
          _position.leverage,
          feeForCancellation,
          address(this)
        );
        return;
      }
    } else if (_expectedPhase == PositionPhase.OPEN_LIMIT) {
      // Limit Orders cannot be triggered if the price is wrong
      require(
        triggerPrices.minPrice <= assetEffectivePrice &&
          triggerPrices.maxPrice >= assetEffectivePrice,
        "PRICE_RANGE"
      );
    } else {
      revert("UNSUPPORTED");
    }

    address poolAccountant = poolAccountantForAsset[
      identifiers.settlementAsset
    ];
    PositionLimitsInfo
      memory positionLimits = storeCorrectLimitsForOpenedPosition(
        _positionId,
        poolAccountant,
        _position.leverage,
        _position.long,
        assetEffectivePrice,
        triggerPrices
      );

    try
      IPoolAccountantFunctionality(poolAccountant).registerOpenTrade(
        _positionId,
        identifiers.trader,
        identifiers.pairId,
        _position.collateral,
        _position.leverage,
        _position.long,
        positionLimits.tp,
        assetEffectivePrice
      )
    returns (uint openFeePart, uint lexFeePart) {
      Position storage _positionStorage = positionsById[_positionId];
      _positionStorage.openPrice = assetEffectivePrice;

      // Store the position's initial collateral
      initialCollateralByPositionId[_positionId] = _position.collateral;

      // Note : Subtracting the open fee before storing the position
      _positionStorage.collateral = _position.collateral - openFeePart;

      // Mark the position as opened
      _positionStorage.phase = PositionPhase.OPENED;
      _positionStorage.inPhaseSince = uint64(block.timestamp);

      registerFeeInternal(
        _positionId,
        identifiers.settlementAsset,
        FeeType.OPEN_FEE,
        openFeePart - lexFeePart
      );
      sendSettlement(
        identifiers.settlementAsset,
        lexPoolForAsset[identifiers.settlementAsset],
        lexFeePart
      );

      delete triggerPricesById[_positionId];

      emit PositionOpened(
        _positionId,
        assetEffectivePrice,
        positionLimits.tp,
        positionLimits.sl,
        openFeePart,
        lexFeePart
      );
    } catch Error(string memory error) {
      revert(error);
    } catch (bytes memory err) {
      if (bytes4(err) == LexErrors.CapError.selector) {
        LexErrors.CapType capType;
        uint256 value;
        assembly {
          capType := mload(add(err, 0x24))
          value := mload(add(err, 0x44))
        }
        emit PositionOpenCancelledByCap(_positionId, capType, value);
        settleCanceledOpenOrderInternal(
          _positionId,
          identifiers.settlementAsset,
          identifiers.trader,
          _position.collateral,
          _position.leverage,
          feeForCancellation,
          address(this)
        );
      } else {
        revert();
      }
    }
  }

  /**
   * Stores the limits values of a newly opened position (after correcting them to the valid ranges if needed)
   */
  function storeCorrectLimitsForOpenedPosition(
    bytes32 positionId,
    address poolAccountant,
    uint32 leverage,
    bool isLong,
    uint64 assetEffectivePrice,
    PositionTriggerPrices memory triggerPrices
  ) internal returns (PositionLimitsInfo memory positionLimits) {
    uint maxGainF = IPoolAccountantV1(poolAccountant).maxGainF();

    positionLimits = positionLimitsInfoById[positionId];

    require(
      positionLimits.tp == 0 || triggerPrices.tpByFraction == 0,
      "MULTIPLE_TP_DEFINITIONS"
    );
    require(
      positionLimits.sl == 0 || triggerPrices.slByFraction == 0,
      "MULTIPLE_SL_DEFINITIONS"
    );

    if (triggerPrices.tpByFraction > 0) {
      uint64 priceDiff = calculatePriceDiffFromFractionAndLeverage(
        assetEffectivePrice,
        triggerPrices.tpByFraction,
        leverage
      );

      positionLimits.tp = isLong
        ? assetEffectivePrice + priceDiff
        : priceDiff < assetEffectivePrice
          ? assetEffectivePrice - priceDiff
          : 0;
    }

    if (triggerPrices.slByFraction > 0) {
      uint64 priceDiff = calculatePriceDiffFromFractionAndLeverage(
        assetEffectivePrice,
        triggerPrices.slByFraction,
        leverage
      );

      positionLimits.sl = isLong
        ? priceDiff < assetEffectivePrice
          ? assetEffectivePrice - priceDiff
          : 0
        : assetEffectivePrice + priceDiff;
    }

    positionLimits.tp = correctTp(
      uint64(maxGainF),
      assetEffectivePrice,
      leverage,
      positionLimits.tp,
      isLong
    );

    positionLimits.tpLastUpdated = uint64(block.timestamp);

    positionLimits.sl = correctSl(
      uint64(maxGainF),
      assetEffectivePrice,
      leverage,
      positionLimits.sl,
      isLong
    );
    positionLimits.slLastUpdated = uint64(block.timestamp);

    // Store
    positionLimitsInfoById[positionId] = positionLimits;
  }

  /**
   * Handles the all closing types of an existing opened position.
   */
  function closeExistingTradeInternal(
    bytes32 _positionId,
    uint effectivePrice,
    PositionCloseType positionCloseType
  )
    internal
    returns (uint tradeValue, int profitPrecision, uint finalClosingPrice)
  {
    PositionIdentifiers memory identifiers = positionIdentifiersById[
      _positionId
    ];

    PoolAccountantStructs.PositionRegistrationParams
      memory positionRegistrationParams = getPositionRegistrationParams(
        _positionId
      );

    require(positionRegistrationParams.collateral > 0, "NO_SUCH_POSITION");

    // Note : 'tradeValue' is the value after subtracting the 'closeFeePart'
    (
      uint closeFeePart,
      uint _tradeValue,
      int _profitPrecision,
      uint _finalClosePrice
    ) = registerTradeCloseInLexInternal(
        _positionId,
        identifiers,
        positionRegistrationParams,
        effectivePrice,
        positionCloseType
      );

    if (_tradeValue > positionRegistrationParams.collateral) {
      uint totalProfitF = ((_tradeValue -
        positionRegistrationParams.collateral) * FRACTION_SCALE) /
        positionRegistrationParams.collateral;
      require(totalProfitF <= maxSanityProfitF, "INVALID_PROFIT");
    }

    profitPrecision = _profitPrecision;
    tradeValue = _tradeValue;
    finalClosingPrice = _finalClosePrice;

    // sanity
    require(
      closeFeePart <= positionRegistrationParams.collateral,
      "CLOSE_FEE_LARGER_THAN_POSITION"
    );
    registerFeeInternal(
      _positionId,
      identifiers.settlementAsset,
      FeeType.CLOSE_FEE,
      closeFeePart
    );

    // Decrease/Remove from the traders
    decreaseOrRemoveFromTradersLists(identifiers.trader);

    // Remove from active position IDs tracking
    removeFromActivePositionIds(identifiers.trader, _positionId);

    // Delete the position
    delete positionsById[_positionId];
    delete positionLimitsInfoById[_positionId];
    delete initialCollateralByPositionId[_positionId];

    // Settle the position
    settleTradeCloseInternal(
      identifiers.trader,
      identifiers.settlementAsset,
      tradeValue,
      positionRegistrationParams.collateral,
      closeFeePart
    );
  }

  // **** LeX-Center Interaction ****

  /**
   * Utility function to inform the "PoolAccountant" that a position is being closed and retrieve it's closing values.
   * @dev Using a separate function to bypass the "stack too depp" issue.
   */
  function registerTradeCloseInLexInternal(
    bytes32 _positionId,
    PositionIdentifiers memory _identifiers,
    PoolAccountantStructs.PositionRegistrationParams
      memory positionRegistrationParams,
    uint closePrice,
    PositionCloseType positionCloseType
  )
    internal
    returns (
      uint closeFeePart,
      uint tradeValue,
      int profitPrecision,
      uint finalClosePrice
    )
  {
    return
      IPoolAccountantFunctionality(
        poolAccountantForAsset[_identifiers.settlementAsset]
      ).registerCloseTrade(
          _positionId,
          _identifiers.trader,
          _identifiers.pairId,
          positionRegistrationParams,
          closePrice,
          positionCloseType
        );
  }

  // **** Trade Closing Settlement ****

  /**
   * Handles the logic for cancellation of a position in any "pending open" for any reason (trader request/timeout/cap error etc...)
   */
  function settleCanceledOpenOrderInternal(
    bytes32 positionId,
    address settlementAsset,
    address trader,
    uint collateral,
    uint32 leverage,
    uint feeF,
    address canceller
  ) internal {
    delete positionsById[positionId];

    delete triggerPricesById[positionId];

    uint cancellationFee = calculateFractionInternal(
      calculateLeveragedPosition(collateral, leverage),
      feeF
    );

    registerFeeInternal(
      positionId,
      settlementAsset,
      FeeType.TRIGGER_FEE,
      cancellationFee
    );

    // Decrease/Remove from the pair traders
    decreaseOrRemoveFromTradersLists(trader);

    // Remove from active position IDs tracking
    removeFromActivePositionIds(trader, positionId);

    uint collateralLeft = collateral - cancellationFee;

    sendSettlement(settlementAsset, trader, collateralLeft);

    emit PendingPositionCancelled(positionId, canceller, cancellationFee);
  }

  /**
   * Handles the asset transferring of a closing position.
   */
  function settleTradeCloseInternal(
    address trader,
    address settlementAsset,
    uint tradeValue,
    uint tradeCollateral,
    uint closingFee
  ) internal {
    ILexPoolV1 lexToken = ILexPoolV1(lexPoolForAsset[settlementAsset]);
    uint assetForTraderFromFloor;

    // Trade gain
    if (tradeValue >= tradeCollateral) {
      // Note : The closing fee stays in the TradingFloor
      assetForTraderFromFloor = tradeCollateral - closingFee;

      uint assetForTraderFromPool = tradeValue - assetForTraderFromFloor;

      lexToken.sendAssetToTrader(trader, assetForTraderFromPool);
    }
    // Trade loss
    else {
      assetForTraderFromFloor = tradeValue;

      uint diff = tradeCollateral - tradeValue;

      if (diff > closingFee) {
        // Send to the lex
        sendSettlement(settlementAsset, address(lexToken), diff - closingFee);
      } else {
        // Take the missing amount for the 'closingFee' from the lex
        lexToken.sendAssetToTrader(address(this), closingFee - diff);
      }
    }

    sendSettlement(settlementAsset, trader, assetForTraderFromFloor);
  }

  // ***** Internal Fees *****

  /**
   * Sends all fees collected in for the SA+FeeType and zeros the counter
   */
  function collectFeeInternal(
    address _asset,
    FeeType _feeType,
    address _to
  ) internal {
    uint amount = feesMap[_asset][_feeType];
    feesMap[_asset][_feeType] = 0;
    IERC20(_asset).safeTransfer(_to, amount);

    emit FeeCollected(_asset, _feeType, _to, amount);
  }

  /**
   * Adds '_amount' to the SA+FeeType counter
   */
  function registerFeeInternal(
    bytes32 _positionId,
    address _token,
    FeeType _feeType,
    uint _amount
  ) internal {
    if (_amount > 0) {
      feesMap[_token][_feeType] += _amount;
      emit FeeRegistered(_positionId, _token, _feeType, _amount);
    }
  }

  // ***** Internal Tokens Utils *****

  /**
   * Utility function to safely take an ERC20 settlement asset from a pre-approved account
   */
  function takeSettlement(
    address settlementAsset,
    address from,
    uint amount
  ) internal {
    if (amount > 0) {
      uint balanceBefore = IERC20(settlementAsset).balanceOf(address(this));
      IERC20(settlementAsset).safeTransferFrom(from, address(this), amount);
      uint balanceAfter = IERC20(settlementAsset).balanceOf(address(this));
      require(balanceAfter - balanceBefore == amount, "DID_NOT_RECEIVE_EXACT");
    }
  }

  /**
   * Utility function to safely send an ERC20 settlement asset to an account
   */
  function sendSettlement(
    address settlementAsset,
    address to,
    uint amount
  ) internal {
    if (amount > 0) {
      IERC20(settlementAsset).safeTransfer(to, amount);
    }
  }

  // ***** Internal State Utils *****

  /**
   * @notice Adds a trader to the global traders array if this is their first position
   * @dev Part of v1.01 global tracking. Called AFTER position is added to activePositionIdsByTrader.
   *      Uses 1-based indexing in tradersIndex mapping (0 = not in array).
   *      This replaces the old per-pair trader tracking system.
   * @param trader The trader address to potentially add to the global array
   */
  function increaseOrAddToTradersLists(address trader) internal {
    // Check if this is the first position for this trader across ALL pairs
    // Note: Position has already been added to activePositionIdsByTrader when this is called
    if (activePositionIdsByTrader[trader].length == 1) {
      // Add trader to global array
      traders.push(trader);
      // Store 1-based index (array position + 1)
      tradersIndex[trader] = traders.length;
    }
    // If not first position, trader is already in the array
  }

  /**
   * @notice Removes a trader from the global array if this is their last position
   * @dev Part of v1.01 global tracking. Called BEFORE position is removed from activePositionIdsByTrader.
   *      Uses swap-and-pop pattern for O(1) removal:
   *      1. Move last trader to the removed trader's position
   *      2. Update the moved trader's index
   *      3. Delete the removed trader's index
   *      4. Pop the last element
   * @param trader The trader address to potentially remove from the global array
   */
  function decreaseOrRemoveFromTradersLists(address trader) internal {
    // Check if this is the last position for this trader across ALL pairs
    // Note: Position has NOT been removed from activePositionIdsByTrader yet
    if (activePositionIdsByTrader[trader].length == 1) {
      // Sanity Checks
      uint256 _traderIndex = tradersIndex[trader];
      if (_traderIndex == 0) {
        // Trader not in the array, SHOULD NOT HAPPEN, a fix for past issue
        emit IncorrectTraderIndex(trader, 0, address(0));
        return;
      }
      if (trader != traders[_traderIndex - 1]) {
        // Index mapping is corrupted, SHOULD NOT HAPPEN, a fix for past issue
        delete tradersIndex[trader];
        emit IncorrectTraderIndex(
          trader,
          _traderIndex,
          traders[_traderIndex - 1]
        );
        return;
      }

      // Use swap-and-pop pattern for O(1) removal
      if (traders.length > 1) {
        // Move last trader to the removed trader's position (convert 1-based to 0-based)
        traders[_traderIndex - 1] = traders[traders.length - 1];
        // Update the moved trader's index to the new position
        tradersIndex[traders[_traderIndex - 1]] = _traderIndex;
      }
      // Clear the removed trader's index (set to 0 = not in array)
      delete tradersIndex[trader];
      // Remove the last element
      traders.pop();
    }
    // If not the last position, keep trader in the global array
  }

  /**
   * @notice Adds a position ID to the trader's active positions array
   * @dev Part of v1.01 global tracking. Maintains a dynamic array of all active
   *      positions for each trader across all pairs. Uses 1-based indexing in
   *      the mapping for efficient existence checks (0 = not in array).
   * @param trader The trader who owns the position
   * @param positionId The position ID to add to the trader's active list
   */
  function addToActivePositionIds(address trader, bytes32 positionId) internal {
    bytes32[] storage activeIds = activePositionIdsByTrader[trader];
    activeIds.push(positionId);
    // Store as 1-based index (array position + 1) for O(1) lookups
    // 0 = not in array, 1 = at array[0], 2 = at array[1], etc.
    positionIdToActivePositionIndex[trader][positionId] = activeIds.length;
  }

  /**
   * @notice Removes a position ID from the trader's active positions array
   * @dev Part of v1.01 global tracking. Uses swap-and-pop pattern for O(1) removal:
   *      1. Get the position's index from the mapping
   *      2. Move the last position ID to this index
   *      3. Update the moved position's index in the mapping
   *      4. Delete the removed position's index
   *      5. Pop the last element
   * @param trader The trader who owns the position
   * @param positionId The position ID to remove from the trader's active list
   */
  function removeFromActivePositionIds(
    address trader,
    bytes32 positionId
  ) internal {
    uint256 storedArrayIndex = positionIdToActivePositionIndex[trader][
      positionId
    ];

    // Only process if the position is in the array (storedArrayIndex > 0)
    if (storedArrayIndex > 0) {
      bytes32[] storage activeIds = activePositionIdsByTrader[trader];

      // Convert from 1-based to 0-based for array access
      uint256 arrayIndex = storedArrayIndex - 1;

      // If not the last element, swap with last
      if (arrayIndex < activeIds.length - 1) {
        bytes32 lastPositionId = activeIds[activeIds.length - 1];
        activeIds[arrayIndex] = lastPositionId;
        // Update the moved element's array index mapping (store as 1-based)
        positionIdToActivePositionIndex[trader][
          lastPositionId
        ] = storedArrayIndex;
      }

      // Remove last element
      activeIds.pop();
      // Clean up the mapping
      delete positionIdToActivePositionIndex[trader][positionId];
    }
  }

  // ***** Internal Calculation Utils *****

  /**
   * Utility function to calculate a 'FRACTION_SCALE' value of a given amount
   * @return The fraction value out of the given amount
   */
  function calculateFractionInternal(
    uint amount,
    uint feeFraction
  ) internal pure returns (uint) {
    return (amount * feeFraction) / FRACTION_SCALE;
  }

  // Trade validity functions

  /**
   * Runs some sanity requires to ensure the position values are in the right range
   */
  function requireValidOpenTradeParameters(
    bool isLong,
    uint minPrice,
    uint maxPrice,
    uint tp,
    uint sl
  ) internal pure {
    require(minPrice <= maxPrice, "MIN_MAX_REVERSE");
    require(tp == 0 || (isLong ? tp > maxPrice : tp < minPrice), "WRONG_TP");
    require(sl == 0 || (isLong ? sl < minPrice : sl > maxPrice), "WRONG_SL");
  }

  /**
   * Receives the wanted sl for a position (with other relevant params) and makes sure the value is within the expected range
   * @notice In case of TP == 0 or a breach of max value, the value returned will be the max allowed value
   *         (can be capped by 0 in case of a SHORT position)
   */
  function correctTp(
    uint64 maxGainF,
    uint64 openPrice,
    uint64 leverage, // scaled up from 32
    uint64 tp,
    bool buy
  ) internal pure returns (uint64) {
    if (
      tp == 0 ||
      currentProfitFraction(maxGainF, openPrice, tp, buy, leverage) >=
      int64(maxGainF)
    ) {
      uint64 tpDiff = uint64(
        ((uint256(openPrice) * uint256(maxGainF)) * LEVERAGE_SCALE) /
          uint256(leverage) /
          FRACTION_SCALE
      );

      return
        buy
          ? openPrice + tpDiff
          : tpDiff <= openPrice
            ? openPrice - tpDiff
            : 0;
    }
    return tp;
  }

  /**
   * Receives the wanted sl for a position (with other relevant params) and makes sure the value is within the expected range
   * @notice In case of SL == 0 or a breach of max value, the value returned will be the max allowed value
   *         (can be capped by 0 in case of a LONG position)
   */
  function correctSl(
    uint64 maxGainF,
    uint64 openPrice,
    uint64 leverage, // scaled up from 32
    uint64 sl,
    bool buy
  ) internal view returns (uint64) {
    if (
      sl == 0 ||
      currentProfitFraction(maxGainF, openPrice, sl, buy, leverage) <=
      int(maxSlF) * -1
    ) {
      uint64 slDiff = uint64(
        (uint256(openPrice) * maxSlF * LEVERAGE_SCALE) /
          uint256(leverage) /
          FRACTION_SCALE
      );

      return
        buy
          ? slDiff <= openPrice
            ? openPrice - slDiff
            : 0
          : openPrice + slDiff;
    }

    return sl;
  }

  /**
   * Calculates the (positive or negative) profit fraction by given position values
   * @return f The profit fraction, with scale of FRACTION_SCALE
   */
  function currentProfitFraction(
    uint64 maxGainF,
    uint64 openPrice,
    uint64 currentPrice,
    bool buy,
    uint64 leverage // scaled from 32
  ) internal pure returns (int64 f) {
    int64 maxPnlF = int64(maxGainF);

    int64 priceDiff = buy
      ? int64(currentPrice) - int64(openPrice)
      : int64(openPrice) - int64(currentPrice);

    int256 nominator = int256(priceDiff) *
      int256(FRACTION_SCALE) *
      int256(int64(leverage));
    int256 longF = nominator /
      int256(LEVERAGE_SCALE) /
      int256(int64(openPrice));

    f = int64(longF);

    f = f > maxPnlF ? maxPnlF : f;
  }

  function calculatePriceDiffFromFractionAndLeverage(
    uint64 originPrice,
    uint64 fractionDiff,
    uint64 leverage
  ) internal pure returns (uint64) {
    uint64 diffInPrice = uint64(
      (uint256(originPrice) * uint256(fractionDiff) * LEVERAGE_SCALE) /
        FRACTION_SCALE /
        uint256(leverage)
    );
    return diffInPrice;
  }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 3 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 4 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

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

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

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 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 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

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

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./AcceptableImplementationClaimableAdminStorage.sol";

/**
 * @title SafeUpgradeableClaimableAdmin
 * @dev based on Compound's Unitroller
 * https://github.com/compound-finance/compound-protocol/blob/a3214f67b73310d547e00fc578e8355911c9d376/contracts/Unitroller.sol
 */
contract AcceptableImplementationClaimableAdmin is
  AcceptableImplementationClaimableAdminStorage
{
  /**
   * @notice Emitted when pendingImplementation is changed
   */
  event NewPendingImplementation(
    address oldPendingImplementation,
    address newPendingImplementation
  );

  /**
   * @notice Emitted when pendingImplementation is accepted, which means delegation implementation is updated
   */
  event NewImplementation(address oldImplementation, address newImplementation);

  /**
   * @notice Emitted when pendingAdmin is changed
   */
  event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

  /**
   * @notice Emitted when pendingAdmin is accepted, which means admin is updated
   */
  event NewAdmin(address oldAdmin, address newAdmin);

  /*** Admin Functions ***/
  function _setPendingImplementation(address newPendingImplementation) public {
    require(msg.sender == admin, "not admin");
    require(
      approvePendingImplementationInternal(newPendingImplementation),
      "INVALID_IMPLEMENTATION"
    );

    address oldPendingImplementation = pendingImplementation;

    pendingImplementation = newPendingImplementation;

    emit NewPendingImplementation(
      oldPendingImplementation,
      pendingImplementation
    );
  }

  /**
   * @notice Accepts new implementation. msg.sender must be pendingImplementation
   * @dev Admin function for new implementation to accept it's role as implementation
   */
  function _acceptImplementation() public returns (uint) {
    // Check caller is pendingImplementation and pendingImplementation ≠ address(0)
    require(
      msg.sender == pendingImplementation &&
        pendingImplementation != address(0),
      "Not the EXISTING pending implementation"
    );

    // Save current values for inclusion in log
    address oldImplementation = implementation;
    address oldPendingImplementation = pendingImplementation;

    implementation = pendingImplementation;

    pendingImplementation = address(0);

    emit NewImplementation(oldImplementation, implementation);
    emit NewPendingImplementation(
      oldPendingImplementation,
      pendingImplementation
    );

    return 0;
  }

  /**
   * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
   * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
   * @param newPendingAdmin New pending admin.
   */
  function _setPendingAdmin(address newPendingAdmin) public {
    // Check caller = admin
    require(msg.sender == admin, "Not Admin");

    // Save current value, if any, for inclusion in log
    address oldPendingAdmin = pendingAdmin;

    // Store pendingAdmin with value newPendingAdmin
    pendingAdmin = newPendingAdmin;

    // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
    emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);
  }

  /**
   * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
   * @dev Admin function for pending admin to accept role and update admin
   */
  function _acceptAdmin() public {
    // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
    require(
      msg.sender == pendingAdmin && pendingAdmin != address(0),
      "Not the EXISTING pending admin"
    );

    // Save current values for inclusion in log
    address oldAdmin = admin;
    address oldPendingAdmin = pendingAdmin;

    // Store admin with value pendingAdmin
    admin = pendingAdmin;

    // Clear the pending value
    pendingAdmin = address(0);

    emit NewAdmin(oldAdmin, admin);
    emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
  }

  constructor(address _initialAdmin) {
    admin = _initialAdmin;
    emit NewAdmin(address(0), _initialAdmin);
  }

  /**
   * @dev Delegates execution to an implementation contract.
   * It returns to the external caller whatever the implementation returns
   * or forwards reverts.
   */
  fallback() external payable {
    // delegate all other functions to current implementation
    (bool success, ) = implementation.delegatecall(msg.data);

    assembly {
      let free_mem_ptr := mload(0x40)
      returndatacopy(free_mem_ptr, 0, returndatasize())

      switch success
      case 0 {
        revert(free_mem_ptr, returndatasize())
      }
      default {
        return(free_mem_ptr, returndatasize())
      }
    }
  }

  receive() external payable {}

  function approvePendingImplementationInternal(
    address // _implementation
  ) internal virtual returns (bool) {
    return true;
  }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

contract ClaimableAdminStorage {
  /**
   * @notice Administrator for this contract
   */
  address public admin;

  /**
   * @notice Pending administrator for this contract
   */
  address public pendingAdmin;

  /*** Modifiers ***/

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

  /*** Constructor ***/

  constructor() {
    // Set admin to caller
    admin = msg.sender;
  }
}

contract AcceptableImplementationClaimableAdminStorage is
  ClaimableAdminStorage
{
  /**
   * @notice Active logic
   */
  address public implementation;

  /**
   * @notice Pending logic
   */
  address public pendingImplementation;
}

contract AcceptableRegistryImplementationClaimableAdminStorage is
  AcceptableImplementationClaimableAdminStorage
{
  /**
   * @notice System Registry
   */
  address public registry;
}

File 10 of 26 : AcceptableRegistryImplementationClaimableAdmin.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./AcceptableImplementationClaimableAdmin.sol";
import "./IContractRegistryBase.sol";

/**
 * @title AcceptableRegistryImplementationClaimableAdmin
 */
contract AcceptableRegistryImplementationClaimableAdmin is
  AcceptableImplementationClaimableAdmin,
  AcceptableRegistryImplementationClaimableAdminStorage
{
  bytes32 public immutable CONTRACT_NAME_HASH;

  constructor(
    address _registry,
    string memory proxyName,
    address _initialAdmin
  ) AcceptableImplementationClaimableAdmin(_initialAdmin) {
    registry = _registry;
    CONTRACT_NAME_HASH = keccak256(abi.encodePacked(proxyName));
  }

  function approvePendingImplementationInternal(
    address _implementation
  ) internal view override returns (bool) {
    return
      IContractRegistryBase(registry).isImplementationValidForProxy(
        CONTRACT_NAME_HASH,
        _implementation
      );
  }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface IContractRegistryBase {
  function isImplementationValidForProxy(
    bytes32 proxyNameHash,
    address _implementation
  ) external view returns (bool);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

/**
 * @dev only use immutables and constants in this contract
 */
contract CommonScales {
  uint256 public constant PRECISION = 1e18; // 18 decimals

  /**
   * @dev scale for leverage.
   * 10,000 = 100x
   * 1,000 = 10x
   * 100 = 1x
   * 10 = 0.1x
   * 1 = 0.01x (smallest unit)
   */
  uint256 public constant LEVERAGE_SCALE = 100; // 2 decimal points

  /**
   * @dev scale for fractions.
   * 100,000 = 100%
   * 100,000 = 10%
   * 1,000 = 1%
   * 100 = 0.1%
   * 10 = 0.01%
   * 1 = 0.001% (smallest unit)
   */
  uint256 public constant FRACTION_SCALE = 100000; // 5 decimal points

  uint256 public constant ACCURACY_IMPROVEMENT_SCALE = 1e9;

  function calculateLeveragedPosition(
    uint256 collateral,
    uint256 leverage
  ) internal pure returns (uint256) {
    return (collateral * leverage) / LEVERAGE_SCALE;
  }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface IFundingRateModel {
  // return value is the "funding paid by heavier side" in PRECISION per OI (heavier side) per second
  // e.g : (0.01 * PRECISION) = Paying (heavier) side (as a whole) pays 1% of funding per second for each OI unit
  function getFundingRate(
    uint256 pairId,
    uint256 openInterestLong,
    uint256 openInterestShort,
    uint256 pairMaxOpenInterest
  ) external view returns (uint256);

  // Get funding rate for a specific accountant (for progressive ramp-up feature)
  function getFundingRateForAccountant(
    address accountant,
    uint256 pairId,
    uint256 openInterestLong,
    uint256 openInterestShort,
    uint256 pairMaxOpenInterest
  ) external view returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface IGlobalLock {
  function lock() external;
  function freeLock() external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface IInterestRateModel {
  // Returns asset/second of interest per borrowed unit
  // e.g : (0.01 * PRECISION) = 1% of interest per second
  function getBorrowRate(uint256 utilization) external view returns (uint256);
}

File 16 of 26 : ILexPoolV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./LexErrors.sol";
import "./LexPoolAdminEnums.sol";
import "./IPoolAccountantV1.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface LexPoolStructs {
  struct PendingDeposit {
    uint256 amount;
    uint256 minAmountOut;
  }

  struct PendingRedeem {
    uint256 amount;
    uint256 minAmountOut;
    uint256 maxAmountOut;
  }
}

interface LexPoolEvents is LexPoolAdminEnums {
  event NewEpoch(
    uint256 epochId,
    int256 reportedUnrealizedPricePnL,
    uint256 exchangeRate,
    uint256 virtualUnderlyingBalance,
    uint256 totalSupply
  );

  event AddressUpdated(LexPoolAddressesEnum indexed enumCode, address a);
  event NumberUpdated(LexPoolNumbersEnum indexed enumCode, uint value);
  event DepositRequest(
    address indexed user,
    uint256 amount,
    uint256 minAmountOut,
    uint256 processingEpoch
  );
  event RedeemRequest(
    address indexed user,
    uint256 amount,
    uint256 minAmountOut,
    uint256 processingEpoch
  );
  event ProcessedDeposit(
    address indexed user,
    bool deposited,
    uint256 depositedAmount
  );
  event ProcessedRedeem(
    address indexed user,
    bool redeemed,
    uint256 withdrawnAmount // Underlying amount
  );
  event CanceledDeposit(
    address indexed user,
    uint256 epoch,
    uint256 cancelledAmount
  );
  event CanceledRedeem(
    address indexed user,
    uint256 epoch,
    uint256 cancelledAmount
  );
  event ImmediateDepositAllowedToggled(bool indexed value);
  event ImmediateDeposit(
    address indexed depositor,
    uint256 depositAmount,
    uint256 mintAmount
  );
  event ReservesWithdrawn(
    address _to,
    uint256 interestShare,
    uint256 totalFundingShare
  );
}

interface ILexPoolFunctionality is
  IERC20,
  LexPoolStructs,
  LexPoolEvents,
  LexErrors
{
  function setPoolAccountant(
    IPoolAccountantFunctionality _poolAccountant
  ) external;

  function setPnlRole(address pnl) external;

  function setMaxExtraWithdrawalAmountF(uint256 maxExtra) external;

  function setEpochsDelayDeposit(uint256 delay) external;

  function setEpochsDelayRedeem(uint256 delay) external;

  function setEpochDuration(uint256 duration) external;

  function setMinDepositAmount(uint256 amount) external;

  function toggleImmediateDepositAllowed() external;

  function reduceReserves(
    address _to
  ) external returns (uint256 interestShare, uint256 totalFundingShare);

  function requestDeposit(
    uint256 amount,
    uint256 minAmountOut,
    bytes32 domain,
    bytes32 referralCode
  ) external;

  function requestDepositViaIntent(
    address user,
    uint256 amount,
    uint256 minAmountOut,
    bytes32 domain,
    bytes32 referralCode
  ) external;

  function requestRedeem(uint256 amount, uint256 minAmountOut) external;

  function requestRedeemViaIntent(
    address user,
    uint256 amount,
    uint256 minAmountOut
  ) external;

  function processDeposit(
    address[] memory users
  )
    external
    returns (
      uint256 amountDeposited,
      uint256 amountCancelled,
      uint256 counterDeposited,
      uint256 counterCancelled
    );

  function cancelDeposits(
    address[] memory users,
    uint256[] memory epochs
  ) external;

  function processRedeems(
    address[] memory users
  )
    external
    returns (
      uint256 amountRedeemed,
      uint256 amountCancelled,
      uint256 counterDeposited,
      uint256 counterCancelled
    );

  function cancelRedeems(
    address[] memory users,
    uint256[] memory epochs
  ) external;

  function nextEpoch(
    int256 totalUnrealizedPricePnL
  ) external returns (uint256 newExchangeRate);

  function currentVirtualUtilization() external view returns (uint256);

  function currentVirtualUtilization(
    uint256 totalBorrows,
    uint256 totalReserves,
    int256 unrealizedFunding
  ) external view returns (uint256);

  function virtualBalanceForUtilization() external view returns (uint256);

  function virtualBalanceForUtilization(
    uint256 extraAmount,
    int256 unrealizedFunding
  ) external view returns (uint256);

  function underlyingBalanceForExchangeRate() external view returns (uint256);

  function sendAssetToTrader(address to, uint256 amount) external;

  function isUtilizationForLPsValid() external view returns (bool);
}

interface ILexPoolV1 is ILexPoolFunctionality {
  function name() external view returns (string memory);

  function symbol() external view returns (string memory);

  function SELF_UNIT_SCALE() external view returns (uint);

  function underlyingDecimals() external view returns (uint256);

  function poolAccountant() external view returns (address);

  function underlying() external view returns (IERC20);

  function tradingFloor() external view returns (address);

  function currentEpoch() external view returns (uint256);

  function currentExchangeRate() external view returns (uint256);

  function nextEpochStartMin() external view returns (uint256);

  function epochDuration() external view returns (uint256);

  function minDepositAmount() external view returns (uint256);

  function epochsDelayDeposit() external view returns (uint256);

  function epochsDelayRedeem() external view returns (uint256);

  function immediateDepositAllowed() external view returns (bool);

  function pendingDeposits(
    uint epoch,
    address account
  ) external view returns (PendingDeposit memory);

  function pendingRedeems(
    uint epoch,
    address account
  ) external view returns (PendingRedeem memory);

  function pendingDepositAmount() external view returns (uint256);

  function pendingWithdrawalAmount() external view returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface ILynxVersionedContract {
  /**
   * @notice Returns the name of the contract
   */
  function getContractName() external view returns (string memory);

  /**
   * @notice Returns the version of the contract
   * @dev units are scaled by 1000 (1,000 = 1.00, 1,120 = 1.12)
   */
  function getContractVersion() external view returns (string memory);
}

File 18 of 26 : IPoolAccountantV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./LexErrors.sol";
import "./ILexPoolV1.sol";
import "./IInterestRateModel.sol";
import "./IFundingRateModel.sol";
import "./TradingEnumsV1.sol";

interface PoolAccountantStructs {
  // @note To be used for passing information in function calls
  struct PositionRegistrationParams {
    uint256 collateral;
    uint32 leverage;
    bool long;
    uint64 openPrice;
    uint64 tp;
  }

  struct PairFunding {
    // Slot 0
    int256 accPerOiLong; // 32 bytes -- Underlying Decimals
    // Slot 1
    int256 accPerOiShort; // 32 bytes -- Underlying Decimals
    // Slot 2
    uint256 lastUpdateTimestamp; // 32 bytes
  }

  struct TradeInitialAccFees {
    // Slot 0
    uint256 borrowIndex; // 32 bytes
    // Slot 1
    int256 funding; // 32 bytes -- underlying units -- Underlying Decimals
  }

  struct PairOpenInterest {
    // Slot 0
    uint256 long; // 32 bytes -- underlying units -- Dynamic open interest for long positions
    // Slot 1
    uint256 short; // 32 bytes -- underlying units -- Dynamic open interest for short positions
  }

  // This struct is not kept in storage
  struct PairFromTo {
    string from;
    string to;
  }

  struct Pair {
    // Slot 0
    uint16 id; // 02 bytes
    uint16 groupId; // 02 bytes
    uint16 feeId; // 02 bytes
    uint32 minLeverage; // 04 bytes
    uint32 maxLeverage; // 04 bytes
    uint32 maxBorrowF; // 04 bytes -- FRACTION_SCALE (5)
    // Slot 1
    uint256 maxPositionSize; // 32 bytes -- underlying units
    // Slot 2
    uint256 maxGain; // 32 bytes -- underlying units
    // Slot 3
    uint256 maxOpenInterest; // 32 bytes -- Underlying units
    // Slot 4
    uint256 maxSkew; // 32 bytes -- underlying units
    // Slot 5
    uint256 minOpenFee; // 32 bytes -- underlying units. MAX_UINT means use the default group level value
    // Slot 6
    uint256 minPerformanceFee; // 32 bytes -- underlying units
  }

  struct Group {
    // Slot 0
    uint16 id; // 02 bytes
    uint32 minLeverage; // 04 bytes
    uint32 maxLeverage; // 04 bytes
    uint32 maxBorrowF; // 04 bytes -- FRACTION_SCALE (5)
    // Slot 1
    uint256 maxPositionSize; // 32 bytes (Underlying units)
    // Slot 2
    uint256 minOpenFee; // 32 bytes (Underlying uints). MAX_UINT means use the default global level value
  }

  struct Fee {
    // Slot 0
    uint16 id; // 02 bytes
    uint32 openFeeF; // 04 bytes -- FRACTION_SCALE (5) (Fraction of leveraged pos)
    uint32 closeFeeF; // 04 bytes -- FRACTION_SCALE (5) (Fraction of leveraged pos)
    uint32 performanceFeeF; // 04 bytes -- FRACTION_SCALE (5) (Fraction of performance)
  }
}

interface PoolAccountantEvents is PoolAccountantStructs {
  event PairAdded(
    uint256 indexed id,
    string indexed from,
    string indexed to,
    Pair pair
  );
  event PairUpdated(uint256 indexed id, Pair pair);

  event GroupAdded(uint256 indexed id, string indexed groupName, Group group);
  event GroupUpdated(uint256 indexed id, Group group);

  event FeeAdded(uint256 indexed id, string indexed name, Fee fee);
  event FeeUpdated(uint256 indexed id, Fee fee);

  event TradeInitialAccFeesStored(
    bytes32 indexed positionId,
    uint256 borrowIndex,
    // uint256 rollover,
    int256 funding
  );

  event AccrueFunding(
    uint256 indexed pairId,
    int256 valueLong,
    int256 valueShort
  );

  event ProtocolFundingShareAccrued(
    uint16 indexed pairId,
    uint256 protocolFundingShare
  );
  // event AccRolloverFeesStored(uint256 pairIndex, uint256 value);

  event FeesCharged(
    bytes32 indexed positionId,
    address indexed trader,
    uint16 indexed pairId,
    PositionRegistrationParams positionRegistrationParams,
    //        bool long,
    //        uint256 collateral, // Underlying Decimals
    //        uint256 leverage,
    int256 profitPrecision, // PRECISION
    uint256 interest,
    int256 funding, // Underlying Decimals
    uint256 closingFee,
    uint256 tradeValue
  );

  event PerformanceFeeCharging(
    bytes32 indexed positionId,
    uint256 performanceFee
  );

  event MaxOpenInterestUpdated(uint256 pairIndex, uint256 maxOpenInterest);

  event AccrueInterest(
    uint256 cash,
    uint256 totalInterestNew,
    uint256 borrowIndexNew,
    uint256 interestShareNew
  );

  event Borrow(
    uint256 indexed pairId,
    uint256 borrowAmount,
    uint256 newTotalBorrows
  );

  event Repay(
    uint256 indexed pairId,
    uint256 repayAmount,
    uint256 newTotalBorrows
  );
}

interface IPoolAccountantFunctionality is
  PoolAccountantStructs,
  PoolAccountantEvents,
  LexErrors,
  TradingEnumsV1
{
  function setTradeIncentivizer(address _tradeIncentivizer) external;

  function setMaxGainF(uint256 _maxGainF) external;

  function setFrm(IFundingRateModel _frm) external;

  function setMinOpenFee(uint256 min) external;

  function setLexPartF(uint256 partF) external;

  function setFundingRateMax(uint256 maxValue) external;

  function setLiquidationThresholdF(uint256 threshold) external;

  function setLiquidationFeeF(uint256 fee) external;

  function setIrm(IInterestRateModel _irm) external;

  function setIrmHard(IInterestRateModel _irm) external;

  function setInterestShareFactor(uint256 factor) external;

  function setFundingShareFactor(uint256 factor) external;

  function setBorrowRateMax(uint256 rate) external;

  function setMaxTotalBorrows(uint256 maxBorrows) external;

  function setMaxVirtualUtilization(uint256 _maxVirtualUtilization) external;

  function resetTradersPairGains(uint256 pairId) external;

  function addGroup(Group calldata _group) external;

  function updateGroup(Group calldata _group) external;

  function addFee(Fee calldata _fee) external;

  function updateFee(Fee calldata _fee) external;

  function addPair(Pair calldata _pair) external;

  function addPairs(Pair[] calldata _pairs) external;

  function updatePair(Pair calldata _pair) external;

  function readAndZeroReserves()
    external
    returns (uint256 accumulatedInterestShare, uint256 accFundingShare);

  function registerOpenTrade(
    bytes32 positionId,
    address trader,
    uint16 pairId,
    uint256 collateral,
    uint32 leverage,
    bool long,
    uint256 tp,
    uint256 openPrice
  ) external returns (uint256 fee, uint256 lexPartFee);

  function registerCloseTrade(
    bytes32 positionId,
    address trader,
    uint16 pairId,
    PositionRegistrationParams calldata positionRegistrationParams,
    uint256 closePrice,
    PositionCloseType positionCloseType
  )
    external
    returns (
      uint256 closingFee,
      uint256 tradeValue,
      int256 profitPrecision,
      uint finalClosePrice
    );

  function registerUpdateTp(
    bytes32 positionId,
    address trader,
    uint16 pairId,
    uint256 collateral,
    uint32 leverage,
    bool long,
    uint256 openPrice,
    uint256 oldTriggerPrice,
    uint256 triggerPrice
  ) external;

  // function registerUpdateSl(
  //     address trader,
  //     uint256 pairIndex,
  //     uint256 index,
  //     uint256 collateral,
  //     uint256 leverage,
  //     bool long,
  //     uint256 openPrice,
  //     uint256 triggerPrice
  // ) external returns (uint256 fee);

  function accrueInterest()
    external
    returns (
      uint256 totalInterestNew,
      uint256 interestShareNew,
      uint256 borrowIndexNew
    );

  // Limited only for the LexPool
  function accrueInterest(
    uint256 availableCash
  )
    external
    returns (
      uint256 totalInterestNew,
      uint256 interestShareNew,
      uint256 borrowIndexNew
    );

  function getTradeClosingValues(
    bytes32 positionId,
    uint16 pairId,
    PositionRegistrationParams calldata positionRegistrationParams,
    uint256 closePrice,
    bool isLiquidation
  )
    external
    returns (
      uint256 tradeValue, // Underlying Decimals
      uint256 safeClosingFee,
      int256 profitPrecision,
      uint256 interest,
      int256 funding
    );

  function getTradeLiquidationPrice(
    bytes32 positionId,
    uint16 pairId,
    uint256 openPrice, // PRICE_SCALE (8)
    uint256 tp,
    bool long,
    uint256 collateral, // Underlying Decimals
    uint32 leverage
  )
    external
    returns (
      uint256 // PRICE_SCALE (8)
    );

  function calcTradeDynamicFees(
    bytes32 positionId,
    uint16 pairId,
    bool long,
    uint256 collateral,
    uint32 leverage,
    uint256 openPrice,
    uint256 tp
  ) external returns (uint256 interest, int256 funding);

  function unrealizedFunding() external view returns (int256);

  function totalBorrows() external view returns (uint256);

  function interestShare() external view returns (uint256);

  function fundingShare() external view returns (uint256);

  function totalReservesView() external view returns (uint256);

  function borrowsAndInterestShare()
    external
    view
    returns (uint256 totalBorrows, uint256 totalInterestShare);

  function pairTotalOpenInterest(
    uint256 pairIndex
  ) external view returns (int256);

  function pricePnL(
    uint256 pairId,
    uint256 price
  ) external view returns (int256);

  function getAllSupportedPairIds() external view returns (uint16[] memory);

  function getAllSupportedGroupsIds() external view returns (uint16[] memory);

  function getAllSupportedFeeIds() external view returns (uint16[] memory);
}

interface IPoolAccountantV1 is IPoolAccountantFunctionality {
  function totalBorrows() external view returns (uint256);

  function maxTotalBorrows() external view returns (uint256);

  function pairBorrows(uint256 pairId) external view returns (uint256);

  function groupBorrows(uint256 groupId) external view returns (uint256);

  function pairMaxBorrow(uint16 pairId) external view returns (uint256);

  function groupMaxBorrow(uint16 groupId) external view returns (uint256);

  function lexPool() external view returns (ILexPoolV1);

  function maxGainF() external view returns (uint256);

  function interestShareFactor() external view returns (uint256);

  function fundingShareFactor() external view returns (uint256);

  function frm() external view returns (IFundingRateModel);

  function irm() external view returns (IInterestRateModel);

  function pairs(uint16 pairId) external view returns (Pair memory);

  function groups(uint16 groupId) external view returns (Group memory);

  function fees(uint16 feeId) external view returns (Fee memory);

  function openInterestInPair(
    uint pairId
  ) external view returns (PairOpenInterest memory);

  function minOpenFee() external view returns (uint256);

  function liquidationThresholdF() external view returns (uint256);

  function liquidationFeeF() external view returns (uint256);

  function lexPartF() external view returns (uint256);

  function tradersPairGains(uint256 pairId) external view returns (int256);

  function calcBorrowAmount(
    uint256 collateral,
    uint256 leverage,
    bool long,
    uint256 openPrice,
    uint256 tp
  ) external pure returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "../../AdministrationContracts/IContractRegistryBase.sol";
import "./IGlobalLock.sol";

interface IRegistryV1Functionality is IContractRegistryBase, IGlobalLock {
  // **** Locking mechanism ****

  function isTradersPortalAndLocker(
    address _address
  ) external view returns (bool);

  function isTriggersAndLocker(address _address) external view returns (bool);

  function isTradersPortalOrTriggersAndLocker(
    address _address
  ) external view returns (bool);
}

interface IRegistryV1 is IRegistryV1Functionality {
  // **** Public Storage params ****

  function feesManagers(address asset) external view returns (address);

  function orderBook() external view returns (address);

  function tradersPortal() external view returns (address);

  function triggers() external view returns (address);

  function tradeIntentsVerifier() external view returns (address);

  function liquidityIntentsVerifier() external view returns (address);

  function chipsIntentsVerifier() external view returns (address);

  function lexProxiesFactory() external view returns (address);

  function chipsFactory() external view returns (address);

  /**
   * @return An array of all supported trading floors
   */
  function getAllSupportedTradingFloors()
    external
    view
    returns (address[] memory);

  /**
   * @return An array of all supported settlement assets
   */
  function getSettlementAssetsForTradingFloor(
    address _tradingFloor
  ) external view returns (address[] memory);

  /**
   * @return The spender role address that is set for this chip
   */
  function getValidSpenderTargetForChipByRole(
    address chip,
    string calldata role
  ) external view returns (address);

  /**
   * @return the address of the valid 'burnHandler' for the chip
   */
  function validBurnHandlerForChip(
    address chip
  ) external view returns (address);

  /**
   * @return The address matching for the given role
   */
  function getDynamicRoleAddress(
    string calldata _role
  ) external view returns (address);
}

File 20 of 26 : ITradingFloorV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./TradingFloorStructsV1.sol";
import "./IPoolAccountantV1.sol";
import "./ILexPoolV1.sol";

interface ITradingFloorV1Functionality is TradingFloorStructsV1 {
  function supportNewSettlementAsset(
    address _asset,
    address _lexPool,
    address _poolAccountant
  ) external;

  function getPositionTriggerInfo(
    bytes32 _positionId
  )
    external
    view
    returns (
      PositionPhase positionPhase,
      uint64 timestamp,
      uint16 pairId,
      bool long,
      uint32 spreadReductionF
    );

  function getPositionPortalInfo(
    bytes32 _positionId
  )
    external
    view
    returns (
      PositionPhase positionPhase,
      uint64 inPhaseSince,
      address positionTrader
    );

  function storePendingPosition(
    OpenOrderType _orderType,
    PositionRequestIdentifiers memory _requestIdentifiers,
    PositionRequestParams memory _requestParams,
    uint32 _spreadReductionF
  ) external returns (bytes32 positionId);

  function setOpenedPositionToMarketClose(
    bytes32 _positionId,
    uint64 _minPrice,
    uint64 _maxPrice
  ) external;

  function cancelPendingPosition(
    bytes32 _positionId,
    OpenOrderType _orderType,
    uint feeFraction
  ) external;

  function cancelMarketCloseForPosition(
    bytes32 _positionId,
    CloseOrderType _orderType,
    uint feeFraction
  ) external;

  function updatePendingPosition_openLimit(
    bytes32 _positionId,
    uint64 _minPrice,
    uint64 _maxPrice,
    uint64 _tp,
    uint64 _sl
  ) external;

  function openNewPosition_market(
    bytes32 _positionId,
    uint64 assetEffectivePrice,
    uint256 feeForCancellation
  ) external;

  function openNewPosition_limit(
    bytes32 _positionId,
    uint64 assetEffectivePrice,
    uint256 feeForCancellation
  ) external;

  function closeExistingPosition_Market(
    bytes32 _positionId,
    uint64 assetPrice,
    uint64 effectivePrice
  ) external;

  function closeExistingPosition_Limit(
    bytes32 _positionId,
    LimitTrigger limitTrigger,
    uint64 assetPrice,
    uint64 effectivePrice
  ) external;

  // Manage open trade
  function updateOpenedPosition(
    bytes32 _positionId,
    PositionField updateField,
    uint64 fieldValue,
    uint64 effectivePrice
  ) external;

  // Fees
  function collectFee(address _asset, FeeType _feeType, address _to) external;
}

interface ITradingFloorV1 is ITradingFloorV1Functionality {
  function PRECISION() external pure returns (uint);

  // *** Views ***

  function deprecated_pairTradersArray(
    address _asset,
    uint _pairIndex
  ) external view returns (address[] memory);

  function traders(uint256 index) external view returns (address);

  function tradersAmount() external view returns (uint256);

  function getNextPositionIndexForTrader(
    address _trader
  ) external view returns (uint32);

  function getActivePositionIdsForTrader(
    address _trader
  ) external view returns (bytes32[] memory);

  function getActivePositionsAmountForTrader(
    address _trader
  ) external view returns (uint256);

  function generatePositionHashId(
    address settlementAsset,
    address trader,
    uint16 pairId,
    uint32 index
  ) external pure returns (bytes32 hashId);

  // *** Public Storage addresses ***

  function lexPoolForAsset(address asset) external view returns (ILexPoolV1);

  function poolAccountantForAsset(
    address asset
  ) external view returns (IPoolAccountantV1);

  function registry() external view returns (address);

  // *** Public Storage params ***

  function positionsById(bytes32 id) external view returns (Position memory);

  function positionIdentifiersById(
    bytes32 id
  ) external view returns (PositionIdentifiers memory);

  function positionLimitsInfoById(
    bytes32 id
  ) external view returns (PositionLimitsInfo memory);

  function triggerPricesById(
    bytes32 id
  ) external view returns (PositionTriggerPrices memory);

  function pairTradersInfo(
    address settlementAsset,
    address trader,
    uint pairId
  ) external view returns (PairTraderInfo memory);

  function spreadReductionsP(uint) external view returns (uint);

  function maxSlF() external view returns (uint);

  function maxTradesPerTrader() external view returns (uint);

  function maxSanityProfitF() external view returns (uint);

  function feesMap(
    address settlementAsset,
    FeeType feeType
  ) external view returns (uint256);
}

File 21 of 26 : LexErrors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface LexErrors {
  enum CapType {
    NONE, // 0
    MIN_OPEN_FEE, // 1
    MAX_POS_SIZE_PAIR, // 2
    MAX_POS_SIZE_GROUP, // 3
    MAX_LEVERAGE, // 4
    MIN_LEVERAGE, // 5
    MAX_VIRTUAL_UTILIZATION, // 6
    MAX_OPEN_INTEREST, // 7
    MAX_ABS_SKEW, // 8
    MAX_BORROW_PAIR, // 9
    MAX_BORROW_GROUP, // 10
    MIN_DEPOSIT_AMOUNT, // 11
    MAX_ACCUMULATED_GAINS, // 12
    BORROW_RATE_MAX, // 13
    FUNDING_RATE_MAX, // 14
    MAX_POTENTIAL_GAIN, // 15
    MAX_TOTAL_BORROW, // 16
    MIN_PERFORMANCE_FEE // 17
    //...
  }
  error CapError(CapType, uint256 value);
}

File 22 of 26 : LexPoolAdminEnums.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

interface LexPoolAdminEnums {
  enum LexPoolAddressesEnum {
    none,
    poolAccountant,
    pnlRole
  }

  enum LexPoolNumbersEnum {
    none,
    maxExtraWithdrawalAmountF,
    epochsDelayDeposit,
    epochsDelayRedeem,
    epochDuration,
    minDepositAmount
  }
}

File 23 of 26 : TradingEnumsV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

interface TradingEnumsV1 {
  enum PositionPhase {
    NONE,
    OPEN_MARKET,
    OPEN_LIMIT,
    OPENED,
    CLOSE_MARKET,
    CLOSED
  }

  enum OpenOrderType {
    NONE,
    MARKET,
    LIMIT
  }
  enum CloseOrderType {
    NONE,
    MARKET
  }
  enum FeeType {
    NONE,
    OPEN_FEE,
    CLOSE_FEE,
    TRIGGER_FEE
  }
  enum LimitTrigger {
    NONE,
    TP,
    SL,
    LIQ
  }
  enum PositionField {
    NONE,
    TP,
    SL
  }

  enum PositionCloseType {
    NONE,
    TP,
    SL,
    LIQ,
    MARKET
  }
}

File 24 of 26 : TradingFloorStructsV1.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "./TradingEnumsV1.sol";

interface TradingFloorStructsV1 is TradingEnumsV1 {
  enum AdminNumericParam {
    NONE,
    MAX_TRADES_PER_TRADER,
    MAX_SL_F,
    MAX_SANITY_PROFIT_F
  }

  /**
   * @dev Memory struct for identifiers
   */
  struct PositionRequestIdentifiers {
    address trader;
    uint16 pairId;
    address settlementAsset;
  }

  /**
   * @dev Memory struct for identifiers
   */
  struct PositionRequestIdentifiers_Old {
    address trader;
    uint16 pairId;
    address settlementAsset;
    uint32 positionIndex;
  }

  struct PositionRequestParams {
    bool long;
    uint256 collateral; // Settlement Asset Decimals
    uint32 leverage;
    uint64 minPrice; // PRICE_SCALE
    uint64 maxPrice; // PRICE_SCALE
    uint64 tp; // PRICE_SCALE
    uint64 sl; // PRICE_SCALE
    uint64 tpByFraction; // FRACTION_SCALE
    uint64 slByFraction; // FRACTION_SCALE
  }

  /**
   * @dev Storage struct for identifiers
   */
  struct PositionIdentifiers {
    // Slot 0
    address settlementAsset; // 20 bytes
    uint16 pairId; // 02 bytes
    uint32 index; // 04 bytes
    // Slot 1
    address trader; // 20 bytes
  }

  struct Position {
    // Slot 0
    uint collateral; // 32 bytes -- Settlement Asset Decimals
    // Slot 1
    PositionPhase phase; // 01 bytes
    uint64 inPhaseSince; // 08 bytes
    uint32 leverage; // 04 bytes
    bool long; // 01 bytes
    uint64 openPrice; // 08 bytes -- PRICE_SCALE (8)
    uint32 spreadReductionF; // 04 bytes -- FRACTION_SCALE (5)
  }

  /**
   * Holds the non liquidation limits for the position
   */
  struct PositionLimitsInfo {
    uint64 tpLastUpdated; // 08 bytes -- timestamp
    uint64 slLastUpdated; // 08 bytes -- timestamp
    uint64 tp; // 08 bytes -- PRICE_SCALE (8)
    uint64 sl; // 08 bytes -- PRICE_SCALE (8)
  }

  /**
   * Holds the prices for opening (and market closing) of a position
   */
  struct PositionTriggerPrices {
    uint64 minPrice; // 08 bytes -- PRICE_SCALE
    uint64 maxPrice; // 08 bytes -- PRICE_SCALE
    uint64 tpByFraction; // 04 bytes -- FRACTION_SCALE
    uint64 slByFraction; // 04 bytes -- FRACTION_SCALE
  }

  /**
   * @dev administration struct, used to keep tracks on the 'PairTraders' list and
   *      to limit the amount of positions a trader can have
   */
  struct PairTraderInfo {
    uint32 deprecated_positionsCounter; // 04 bytes - DEPRECATED: Use activePositionIdsByTrader.length instead
    uint32 positionInArray; // 04 bytes (the index + 1)
    //! Note : Can NOT (!) add more fields here
  }
}

File 25 of 26 : TradingFloorProxy.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "../../AdministrationContracts/AcceptableRegistryImplementationClaimableAdmin.sol";

/**
 * @title TradingFloorProxy
 * @dev Used as the upgradable brain of the Lynx platform
 */
contract TradingFloorProxy is AcceptableRegistryImplementationClaimableAdmin {
  constructor(
    address _registry
  )
    AcceptableRegistryImplementationClaimableAdmin(
      _registry,
      "TradingFloor",
      msg.sender
    )
  {}
}

File 26 of 26 : TradingFloorStorage.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import "../../AdministrationContracts/AcceptableImplementationClaimableAdminStorage.sol";
import "../interfaces/ITradingFloorV1.sol";
import "../Common/CommonScales.sol";

/**
 * @title TradingFloorStorageV1
 * @dev Storage contract for the TradingFloor
 */
contract TradingFloorV1Storage is
  AcceptableRegistryImplementationClaimableAdminStorage,
  TradingFloorStructsV1,
  CommonScales
{
  // ***** Trading variables *****

  // Maximum number of open positions a trader can have globally across all pairs
  // Replaces the old maxTradesPerPair with global position limiting
  uint public maxTradesPerTrader;

  uint public maxSlF; // FRACTION_SCALE (5)

  uint public maxSanityProfitF; // FRACTION_SCALE (5)

  // ***** Pair pausing *****

  mapping(uint => bool) public pausedPairs;

  // ***** Fees *****

  // Token => Fee Type => Amount
  mapping(address => mapping(FeeType => uint)) public feesMap;

  // ***** Lex&Accountant *****

  // settlement asset => lex pool
  mapping(address => address) public lexPoolForAsset;
  // settlement asset => pool accountant
  mapping(address => address) public poolAccountantForAsset;

  // ***** Position Identifiers *****

  // position id => PositionIdentifiers struct
  mapping(bytes32 => PositionIdentifiers) public positionIdentifiersById;

  // ***** Positions *****

  // position id => Position Struct
  mapping(bytes32 => Position) public positionsById;

  // position id => OpenTradeInfo struct
  mapping(bytes32 => PositionLimitsInfo) public positionLimitsInfoById;

  // position id => trigger prices
  mapping(bytes32 => PositionTriggerPrices) public triggerPricesById;

  // Position id => initial collateral
  mapping(bytes32 => uint) public initialCollateralByPositionId;

  // ***** DEPRECATED: Per-pair trader tracking (kept for backward compatibility) *****
  // asset => pair id => traders list
  mapping(address => mapping(uint => address[])) public deprecated_pairTraders;
  // asset => trader => pair id => index in traders list
  mapping(address => mapping(address => mapping(uint => PairTraderInfo)))
    public deprecated_pairTradersInfo;

  // ***** NEW: Global trader tracking system (introduced in v1.01) *****

  // Global array of all traders with active positions across any pair
  // Traders are added when opening their first position and removed when closing their last
  address[] public traders;

  // Maps trader address to their index in the traders array (1-based indexing)
  // 0 = not in array (default), 1 = at array[0], 2 = at array[1], etc.
  // This enables O(1) existence checks and efficient array management
  mapping(address => uint) public tradersIndex;

  // Tracks the last used position index for generating unique position IDs
  // Increments with each new position opened by the trader
  mapping(address => uint32) public pairTradersLastUsedPositionIndex;

  // Maps trader to their list of active position IDs across all pairs
  // Enables efficient iteration through only active positions for a trader
  // Positions are added on open and removed on close using swap-and-pop
  mapping(address => bytes32[]) public activePositionIdsByTrader;

  // Maps position ID to its index in the trader's activePositionIdsByTrader array (1-based)
  // 0 = not in array, 1 = at array[0], etc.
  // Enables O(1) removal from activePositionIdsByTrader when closing positions
  mapping(address => mapping(bytes32 => uint256))
    public positionIdToActivePositionIndex;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "metadata": {
    "useLiteralContent": true
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"enum LexErrors.CapType","name":"","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"CapError","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"enum TradingEnumsV1.FeeType","name":"feeType","type":"uint8"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"enum TradingEnumsV1.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"traderIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"foundTraderAddress","type":"address"}],"name":"IncorrectTraderIndex","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"NumberUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"uint16","name":"pairId","type":"uint16"},{"indexed":false,"internalType":"bool","name":"buy","type":"bool"},{"indexed":true,"internalType":"enum TradingEnumsV1.PositionField","name":"updatedField","type":"uint8"},{"indexed":false,"internalType":"uint64","name":"fieldValue","type":"uint64"}],"name":"OpenedPositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pairId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PairPausedChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PendingPositionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"enum TradingEnumsV1.PositionPhase","name":"phase","type":"uint8"},{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"address","name":"settlementAsset","type":"address"},{"internalType":"uint32","name":"positionIndex","type":"uint32"}],"indexed":false,"internalType":"struct TradingFloorStructsV1.PositionRequestIdentifiers_Old","name":"requestIdentifiers","type":"tuple"},{"components":[{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint32","name":"leverage","type":"uint32"},{"internalType":"uint64","name":"minPrice","type":"uint64"},{"internalType":"uint64","name":"maxPrice","type":"uint64"},{"internalType":"uint64","name":"tp","type":"uint64"},{"internalType":"uint64","name":"sl","type":"uint64"},{"internalType":"uint64","name":"tpByFraction","type":"uint64"},{"internalType":"uint64","name":"slByFraction","type":"uint64"}],"indexed":false,"internalType":"struct TradingFloorStructsV1.PositionRequestParams","name":"requestParams","type":"tuple"},{"indexed":false,"internalType":"uint32","name":"_spreadReductionF","type":"uint32"}],"name":"PendingPositionStored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"enum TradingEnumsV1.PositionPhase","name":"phase","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"index","type":"uint32"},{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"address","name":"settlementAsset","type":"address"}],"indexed":false,"internalType":"struct TradingFloorStructsV1.PositionRequestIdentifiers","name":"requestIdentifiers","type":"tuple"},{"components":[{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint32","name":"leverage","type":"uint32"},{"internalType":"uint64","name":"minPrice","type":"uint64"},{"internalType":"uint64","name":"maxPrice","type":"uint64"},{"internalType":"uint64","name":"tp","type":"uint64"},{"internalType":"uint64","name":"sl","type":"uint64"},{"internalType":"uint64","name":"tpByFraction","type":"uint64"},{"internalType":"uint64","name":"slByFraction","type":"uint64"}],"indexed":false,"internalType":"struct TradingFloorStructsV1.PositionRequestParams","name":"requestParams","type":"tuple"},{"indexed":false,"internalType":"uint32","name":"_spreadReductionF","type":"uint32"}],"name":"PendingPositionStoredV1010","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"tp","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"sl","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"minPrice","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"maxPrice","type":"uint64"}],"name":"PendingPositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"enum TradingEnumsV1.LimitTrigger","name":"limitTrigger","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"triggerPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"effectiveClosePrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tradeValue","type":"uint256"},{"indexed":false,"internalType":"int256","name":"profitPrecision","type":"int256"}],"name":"PositionClosedLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"triggerPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tradeValue","type":"uint256"},{"indexed":false,"internalType":"int256","name":"profitPrecision","type":"int256"}],"name":"PositionClosedMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"components":[{"internalType":"address","name":"settlementAsset","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"uint32","name":"index","type":"uint32"},{"internalType":"address","name":"trader","type":"address"}],"indexed":false,"internalType":"struct TradingFloorStructsV1.PositionIdentifiers","name":"identifiers","type":"tuple"}],"name":"PositionIdentifiersStored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PositionMarketCloseCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"enum LexErrors.CapType","name":"capType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"PositionOpenCancelledByCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"triggerPrice","type":"uint64"}],"name":"PositionOpenCancelledByMarketPriceRange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"openPrice","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"tp","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"sl","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"totalOpenFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lexFeePart","type":"uint256"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"_minPrice","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"_maxPrice","type":"uint64"}],"name":"PositionSetForMarketClose","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"lexPool","type":"address"},{"indexed":true,"internalType":"address","name":"poolAccountant","type":"address"}],"name":"SettlementAssetAdded","type":"event"},{"inputs":[],"name":"ACCURACY_IMPROVEMENT_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTRACT_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRACTION_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEVERAGE_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_FRACTION_FOR_CANCEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TradingFloorProxy","name":"tradingFloorProxy","type":"address"}],"name":"_become","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"activePositionIdsByTrader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"enum TradingEnumsV1.CloseOrderType","name":"_orderType","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"cancelMarketCloseForPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"enum TradingEnumsV1.OpenOrderType","name":"_orderType","type":"uint8"},{"internalType":"uint256","name":"feeFraction","type":"uint256"}],"name":"cancelPendingPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"enum TradingEnumsV1.LimitTrigger","name":"limitTrigger","type":"uint8"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"uint64","name":"effectivePrice","type":"uint64"}],"name":"closeExistingPosition_Limit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"uint64","name":"effectivePrice","type":"uint64"}],"name":"closeExistingPosition_Market","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"enum TradingEnumsV1.FeeType","name":"_feeType","type":"uint8"},{"internalType":"address","name":"_to","type":"address"}],"name":"collectFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"deprecated_pairTraders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_pairIndex","type":"uint256"}],"name":"deprecated_pairTradersArray","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"deprecated_pairTradersInfo","outputs":[{"internalType":"uint32","name":"deprecated_positionsCounter","type":"uint32"},{"internalType":"uint32","name":"positionInArray","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"enum TradingEnumsV1.FeeType","name":"","type":"uint8"}],"name":"feesMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"settlementAsset","type":"address"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"uint32","name":"index","type":"uint32"}],"name":"generatePositionHashId","outputs":[{"internalType":"bytes32","name":"hashId","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getActivePositionIdsForTrader","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getActivePositionsAmountForTrader","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getContractVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_trader","type":"address"}],"name":"getNextPositionIndexForTrader","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionPortalInfo","outputs":[{"internalType":"enum TradingEnumsV1.PositionPhase","name":"positionPhase","type":"uint8"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"address","name":"trader","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionRegistrationParams","outputs":[{"components":[{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint32","name":"leverage","type":"uint32"},{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint64","name":"openPrice","type":"uint64"},{"internalType":"uint64","name":"tp","type":"uint64"}],"internalType":"struct PoolAccountantStructs.PositionRegistrationParams","name":"registrationParams","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"}],"name":"getPositionTriggerInfo","outputs":[{"internalType":"enum TradingEnumsV1.PositionPhase","name":"positionPhase","type":"uint8"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint32","name":"spreadReductionF","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"initialCollateralByPositionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"settlementAsset","type":"address"}],"name":"isSettlementAssetSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lexPoolForAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSanityProfitF","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSlF","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTradesPerTrader","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint64","name":"assetEffectivePrice","type":"uint64"},{"internalType":"uint256","name":"feeForCancellation","type":"uint256"}],"name":"openNewPosition_limit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint64","name":"assetEffectivePrice","type":"uint64"},{"internalType":"uint256","name":"feeForCancellation","type":"uint256"}],"name":"openNewPosition_market","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pairTradersLastUsedPositionIndex","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pausedPairs","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolAccountantForAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positionIdToActivePositionIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positionIdentifiersById","outputs":[{"internalType":"address","name":"settlementAsset","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"uint32","name":"index","type":"uint32"},{"internalType":"address","name":"trader","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positionLimitsInfoById","outputs":[{"internalType":"uint64","name":"tpLastUpdated","type":"uint64"},{"internalType":"uint64","name":"slLastUpdated","type":"uint64"},{"internalType":"uint64","name":"tp","type":"uint64"},{"internalType":"uint64","name":"sl","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positionsById","outputs":[{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"enum TradingEnumsV1.PositionPhase","name":"phase","type":"uint8"},{"internalType":"uint64","name":"inPhaseSince","type":"uint64"},{"internalType":"uint32","name":"leverage","type":"uint32"},{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint64","name":"openPrice","type":"uint64"},{"internalType":"uint32","name":"spreadReductionF","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint64","name":"_minPrice","type":"uint64"},{"internalType":"uint64","name":"_maxPrice","type":"uint64"}],"name":"setOpenedPositionToMarketClose","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pairId","type":"uint256"},{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setPairPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum TradingFloorStructsV1.AdminNumericParam","name":"numericParam","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setTradeParam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum TradingEnumsV1.OpenOrderType","name":"_orderType","type":"uint8"},{"components":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint16","name":"pairId","type":"uint16"},{"internalType":"address","name":"settlementAsset","type":"address"}],"internalType":"struct TradingFloorStructsV1.PositionRequestIdentifiers","name":"_requestIdentifiers","type":"tuple"},{"components":[{"internalType":"bool","name":"long","type":"bool"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint32","name":"leverage","type":"uint32"},{"internalType":"uint64","name":"minPrice","type":"uint64"},{"internalType":"uint64","name":"maxPrice","type":"uint64"},{"internalType":"uint64","name":"tp","type":"uint64"},{"internalType":"uint64","name":"sl","type":"uint64"},{"internalType":"uint64","name":"tpByFraction","type":"uint64"},{"internalType":"uint64","name":"slByFraction","type":"uint64"}],"internalType":"struct TradingFloorStructsV1.PositionRequestParams","name":"_requestParams","type":"tuple"},{"internalType":"uint32","name":"_spreadReductionF","type":"uint32"}],"name":"storePendingPosition","outputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_lexPool","type":"address"},{"internalType":"address","name":"_poolAccountant","type":"address"}],"name":"supportNewSettlementAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"traders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradersAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tradersIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"triggerPricesById","outputs":[{"internalType":"uint64","name":"minPrice","type":"uint64"},{"internalType":"uint64","name":"maxPrice","type":"uint64"},{"internalType":"uint64","name":"tpByFraction","type":"uint64"},{"internalType":"uint64","name":"slByFraction","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"},{"internalType":"enum TradingEnumsV1.PositionField","name":"updateField","type":"uint8"},{"internalType":"uint64","name":"fieldValue","type":"uint64"},{"internalType":"uint64","name":"effectivePrice","type":"uint64"}],"name":"updateOpenedPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_positionId","type":"bytes32"},{"internalType":"uint64","name":"_minPrice","type":"uint64"},{"internalType":"uint64","name":"_maxPrice","type":"uint64"},{"internalType":"uint64","name":"_tp","type":"uint64"},{"internalType":"uint64","name":"_sl","type":"uint64"}],"name":"updatePendingPosition_openLimit","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50600080546001600160a01b03191633179055615c8f80620000336000396000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c806382571409116101de578063b71f3cfe1161010f578063ece938cf116100ad578063f555f6971161007c578063f555f69714610aed578063f5f5ba7214610b0d578063f851a44014610b37578063f9b9484e14610b4a57600080fd5b8063ece938cf14610a5b578063ef6ecc5514610a64578063f2eb245e14610ac4578063f51f3fd314610ae457600080fd5b8063ddf474f1116100e9578063ddf474f1146109cd578063e640f33b14610a15578063eb48914014610a28578063ec7f8a3a14610a3b57600080fd5b8063b71f3cfe1461099c578063c07f9921146109a7578063ca3a3a82146109ba57600080fd5b806395be50501161017c578063a40d726811610156578063a40d726814610947578063aaf5eb681461095a578063acfd6b9214610969578063ad1f2b561461099457600080fd5b806395be5050146108a65780639ff69ffa14610921578063a2a25ea61461093457600080fd5b80638f7a8fb5116101b85780638f7a8fb5146107e257806390f24cac1461085d57806393a7f6a71461087057806394a1e6e51461089e57600080fd5b806382571409146107a657806386dc4975146107af5780638aa10435146107c257600080fd5b8063396f7b23116102c357806368f296a51161026157806376d901be1161023057806376d901be146107435780637b1039991461077657806380193b261461078957806380a7f3d41461079357600080fd5b806368f296a5146106c15780636e01af8d146106e7578063725b7d52146106fa57806374d8b78e1461071a57600080fd5b80634ebe5c331161029d5780634ebe5c33146105f35780635c60da1b14610606578063614d08f81461061957806366307a4f1461064657600080fd5b8063396f7b23146105ad5780633ad6f124146105c05780633b17a497146105d357600080fd5b80631ea9af6b1161033057806324b22a1f1161030a57806324b22a1f1461052c578063267822471461053f57806330d073d01461055257806338b903331461057d57600080fd5b80631ea9af6b146104e95780632457bc3a146104fc5780632485f3f11461050457600080fd5b8063135e563d1161036c578063135e563d1461048557806318fa4714146104985780631961aba0146104ad5780631d504dc6146104d657600080fd5b8063010570851461039357806303b90a87146103b9578063042e37c5146103fa575b600080fd5b6103a66103a1366004614fdf565b610bac565b6040519081526020015b60405180910390f35b6103e26103c7366004615123565b600b602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103b0565b610449610408366004615140565b600c60205260009081526040902080546001909101546001600160a01b0380831692600160a01b810461ffff1692600160b01b90910463ffffffff16911684565b604080516001600160a01b03958616815261ffff909416602085015263ffffffff909216918301919091529190911660608201526080016103b0565b6103e2610493366004615140565b611107565b6104ab6104a6366004615166565b611131565b005b6103a66104bb366004615123565b6001600160a01b031660009081526016602052604090205490565b6104ab6104e4366004615123565b611200565b6104ab6104f73660046151b1565b61134e565b6013546103a6565b610517610512366004615123565b6113e4565b60405163ffffffff90911681526020016103b0565b6104ab61053a3660046151e6565b61147e565b6001546103e2906001600160a01b031681565b6103a6610560366004615212565b600960209081526000928352604080842090915290825290205481565b6105a0604051806040016040528060048152602001630c4c0c4d60e21b81525081565b6040516103b0919061526f565b6003546103e2906001600160a01b031681565b6103a66105ce3660046152a2565b61171d565b6105e66105e1366004615123565b61174e565b6040516103b091906152c0565b6104ab610601366004615304565b6117ba565b6002546103e2906001600160a01b031681565b6105a06040518060400160405280600e81526020016d54726164696e67466c6f6f72563160901b81525081565b61068e610654366004615140565b600e602052600090815260409020546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b604080516001600160401b03958616815293851660208501529184169183019190915290911660608201526080016103b0565b6105176106cf366004615123565b60156020526000908152604090205463ffffffff1681565b6104ab6106f5366004615340565b61187e565b61070d6107083660046152a2565b611c14565b6040516103b09190615367565b6103e2610728366004615123565b600a602052600090815260409020546001600160a01b031681565b610766610751366004615140565b60086020526000908152604090205460ff1681565b60405190151581526020016103b0565b6004546103e2906001600160a01b031681565b6103a6620186a081565b6104ab6107a13660046153a8565b611c94565b6103a660075481565b6104ab6107bd3660046153ec565b6120e6565b6040805180820190915260048152630c4c0c4d60e21b60208201526105a0565b61084a6107f0366004615140565b600d602052600090815260409020805460019091015460ff808216916001600160401b03610100820481169263ffffffff600160481b8404811693600160681b810490921692600160701b83041691600160b01b90041687565b6040516103b0979695949392919061543b565b6103e261086b366004615490565b612179565b61076661087e366004615123565b6001600160a01b039081166000908152600a602052604090205416151590565b6103a66121be565b6109106108b4366004615140565b6000908152600d6020818152604080842060010154600c835293205491905260ff8083169361010084046001600160401b031693600160a01b90930461ffff1692600160681b810490921691600160b01b900463ffffffff1690565b6040516103b09594939291906154c5565b6104ab61092f366004615509565b6121cf565b6104ab610942366004615567565b612416565b6103a6610955366004615597565b612538565b6103a6670de0b6b3a764000081565b6103a66109773660046152a2565b601760209081526000928352604080842090915290825290205481565b6103a6606481565b6103a6633b9aca0081565b6104ab6109b53660046155e4565b6125a7565b6104ab6109c836600461560c565b612c64565b61068e6109db366004615140565b600f602052600090815260409020546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b6104ab610a2336600461560c565b612e15565b6104ab610a363660046151b1565b612fa6565b6103a6610a49366004615123565b60146020526000908152604090205481565b6103a660055481565b610aa7610a72366004615648565b601260209081526000938452604080852082529284528284209052825290205463ffffffff8082169164010000000090041682565b6040805163ffffffff9384168152929091166020830152016103b0565b6103a6610ad2366004615140565b60106020526000908152604090205481565b6103a660065481565b610b00610afb366004615140565b61303c565b6040516103b091906156bf565b60408051808201909152600e81526d54726164696e67466c6f6f72563160901b60208201526105a0565b6000546103e2906001600160a01b031681565b610b9d610b58366004615140565b6000908152600d60209081526040808320600190810154600c90935292209091015460ff8216926101009092046001600160401b0316916001600160a01b0390911690565b6040516103b0939291906156cd565b6004805460405163731aa5f960e01b815233928101929092526000916001600160a01b039091169063731aa5f990602401602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e9190615703565b610c435760405162461bcd60e51b8152600401610c3a90615720565b60405180910390fd5b610c6b84604001516001600160a01b039081166000908152600a602052604090205416151590565b610cb75760405162461bcd60e51b815260206004820152601e60248201527f4e4f4e5f535550504f525445445f534554544c454d454e545f415353455400006044820152606401610c3a565b60208085015161ffff1660009081526008909152604090205460ff1615610cf05760405162461bcd60e51b8152600401610c3a90615748565b6001856002811115610d0457610d04615411565b1480610d2157506002856002811115610d1f57610d1f615411565b145b610d665760405162461bcd60e51b8152602060048201526016602482015275554e535550504f525445445f4f524445525f5459504560501b6044820152606401610c3a565b610dab836000015184606001516001600160401b031685608001516001600160401b03168660a001516001600160401b03168760c001516001600160401b0316613164565b60055484516001600160a01b031660009081526016602052604090205410610e0d5760405162461bcd60e51b815260206004820152601560248201527426a0ac2faa2920a222a9afa822a92faa2920a222a960591b6044820152606401610c3a565b6000610e26856040015186600001518760200151613246565b8092508193505050610e458560400151866000015186602001516133b7565b8451610e50906134fc565b6000828152600d60205260409020805415610e975760405162461bcd60e51b8152602060048201526007602482015266125117d554d15160ca1b6044820152606401610c3a565b600180820180548751604089015163ffffffff908116600160481b026cffffffff00000000000000000019921515600160681b0260ff60681b19928b16600160b01b02929092166cffffffff0000000000000000ff60681b1990941693909317171617905560208601518255600090886002811115610f1857610f18615411565b14610f24576002610f27565b60015b9050808260010160006101000a81548160ff02191690836005811115610f4f57610f4f615411565b0217905550428260010160016101000a8154816001600160401b0302191690836001600160401b031602179055506000600e600086815260200190815260200160002090508660a001518160000160106101000a8154816001600160401b0302191690836001600160401b031602179055508660c001518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055506000600f6000878152602001908152602001600020905087606001518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555087608001518160000160086101000a8154816001600160401b0302191690836001600160401b031602179055508760e001518160000160106101000a8154816001600160401b0302191690836001600160401b031602179055508761010001518160000160186101000a8154816001600160401b0302191690836001600160401b03160217905550857f835de04f5a930b169d6564c8f1c5f91f89abd9ea026b7488c94452abb900cc7484878c8c8c6040516110f295949392919061576d565b60405180910390a25050505050949350505050565b6013818154811061111757600080fd5b6000918252602090912001546001600160a01b0316905081565b6004805460405163a8e36e5b60e01b81526001600160a01b038681169382019390935291169063a8e36e5b90602401602060405180830381865afa15801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a19190615851565b6001600160a01b0316336001600160a01b0316146111f05760405162461bcd60e51b815260206004820152600c60248201526b10a332b2b9a6b0b730b3b2b960a11b6044820152606401610c3a565b6111fb838383613578565b505050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112629190615851565b6001600160a01b0316336001600160a01b0316146112b15760405162461bcd60e51b815260206004820152600c60248201526b10b83937bc3c9730b236b4b760a11b6044820152606401610c3a565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af11580156112f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611315919061586e565b1561134b5760405162461bcd60e51b8152600401610c3a9060208082526004908201526319985a5b60e21b604082015260600190565b50565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190615703565b6113d75760405162461bcd60e51b8152600401610c3a90615887565b6111fb836002848461369b565b6001600160a01b03811660009081526015602052604081205463ffffffff9081169081106114545760405162461bcd60e51b815260206004820152601760248201527f504f534954494f4e5f494e4445585f4f564552464c4f570000000000000000006044820152606401610c3a565b600b8163ffffffff16101561146c5750600b92915050565b6114778160016158c0565b9392505050565b6000546001600160a01b031633146114c55760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa0a226a4a760b11b6044820152606401610c3a565b600081116115065760405162461bcd60e51b815260206004820152600e60248201526d43414e4e4f545f42455f5a45524f60901b6044820152606401610c3a565b6060600183600381111561151c5761151c615411565b03611555575060408051808201909152601281527136b0bc2a3930b232b9a832b92a3930b232b960711b602082015260058290556116d0565b600283600381111561156957611569615411565b036115f857606461157e620186a060326158e4565b6115889190615911565b8210156115d15760405162461bcd60e51b81526020600482015260176024820152762a2920a222afa820a920a6afa922a9aa2924a1aa24a7a760491b6044820152606401610c3a565b506040805180820190915260068082526536b0bc29b62360d11b60208301528290556116d0565b600383600381111561160c5761160c615411565b0361169a5761161f620186a060026158e4565b8210156116685760405162461bcd60e51b81526020600482015260176024820152762a2920a222afa820a920a6afa922a9aa2924a1aa24a7a760491b6044820152606401610c3a565b5060408051808201909152601081526f36b0bc29b0b734ba3ca83937b334ba2360811b602082015260078290556116d0565b60405162461bcd60e51b815260206004820152600b60248201526a155394d5541413d495115160aa1b6044820152606401610c3a565b806040516116de9190615925565b604051908190038120838252907f8cf3e35f6221b16e1670a3413180c9484bf5aa71787905909fa82a6a2662e9ab9060200160405180910390a2505050565b6016602052816000526040600020818154811061173957600080fd5b90600052602060002001600091509150505481565b6001600160a01b0381166000908152601660209081526040918290208054835181840281018401909452808452606093928301828280156117ae57602002820191906000526020600020905b81548152602001906001019080831161179a575b50505050509050919050565b6004805460405163419a519360e01b815233928101929092526001600160a01b03169063419a519390602401602060405180830381865afa158015611803573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118279190615703565b6118735760405162461bcd60e51b815260206004820152601a60248201527f212854726164657273506f7274616c7c7c5472696767657273290000000000006044820152606401610c3a565b6111fb338484613d2f565b6004805460405163419a519360e01b815233928101929092526001600160a01b03169063419a519390602401602060405180830381865afa1580156118c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118eb9190615703565b6119375760405162461bcd60e51b815260206004820152601a60248201527f212854726164657273506f7274616c7c7c5472696767657273290000000000006044820152606401610c3a565b6119456064620186a0615911565b81111561198b5760405162461bcd60e51b81526020600482015260146024820152734645455f4652414354494f4e5f544f4f5f42494760601b6044820152606401610c3a565b6000838152600d60209081526040808320815160e08101909252805482526001810154919290919083019060ff1660058111156119ca576119ca615411565b60058111156119db576119db615411565b8152600191909101546001600160401b036101008204811660208085019190915263ffffffff600160481b8404811660408087019190915260ff600160681b86041615156060870152600160701b85049093166080860152600160b01b90930490921660a0909301929092526000878152600d9091522054909150611a725760405162461bcd60e51b8152600401610c3a90615941565b6000848152600c6020908152604091829020825160808101845281546001600160a01b038082168352600160a01b820461ffff1694830194909452600160b01b900463ffffffff16938101939093526001908101549091166060830152846002811115611ae157611ae1615411565b03611b4357600182602001516005811115611afe57611afe615411565b14611b3e5760405162461bcd60e51b815260206004820152601060248201526f2727aa2fa6a0a925a2aa2fa7a92222a960811b6044820152606401610c3a565b611bee565b6002846002811115611b5757611b57615411565b03611bb357600282602001516005811115611b7457611b74615411565b14611b3e5760405162461bcd60e51b815260206004820152600f60248201526e2727aa2fa624a6a4aa2fa7a92222a960891b6044820152606401610c3a565b60405162461bcd60e51b815260206004820152601060248201526f57524f4e475f4f524445525f5459504560801b6044820152606401610c3a565b611c0d8582600001518360600151856000015186606001518833613e40565b5050505050565b6001600160a01b0382166000908152601160209081526040808320848452825291829020805483518184028101840190945280845260609392830182828015611c8657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c68575b505050505090505b92915050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015611cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d019190615703565b611d1d5760405162461bcd60e51b8152600401610c3a90615887565b6000848152600d60209081526040808320815160e08101909252805482526001810154919290919083019060ff166005811115611d5c57611d5c615411565b6005811115611d6d57611d6d615411565b8152600191909101546001600160401b0361010082048116602084015263ffffffff600160481b83048116604085015260ff600160681b84041615156060850152600160701b83049091166080840152600160b01b9091041660a0909101528051909150611ded5760405162461bcd60e51b8152600401610c3a90615941565b6000858152600e60209081526040808320815160808101835290546001600160401b038082168352600160401b8204811694830194909452600160801b8104841692820192909252600160c01b90910490911660608201529080806002886003811115611e5c57611e5c615411565b03611eb9578460800151611e895783606001516001600160401b0316866001600160401b03161015611ea4565b83606001516001600160401b0316866001600160401b031611155b925050506001600160401b0384166002611f9e565b6001886003811115611ecd57611ecd615411565b03611f30578460800151611efa5783604001516001600160401b0316866001600160401b03161115611f15565b83604001516001600160401b0316866001600160401b031610155b925083604001516001600160401b0316915060019050611f9e565b6003886003811115611f4457611f44615411565b03611f60575060019150506001600160401b0384166003611f9e565b60405162461bcd60e51b81526020600482015260136024820152722ba927a723afa624a6a4aa2faa2924a3a3a2a960691b6044820152606401610c3a565b82611fdb5760405162461bcd60e51b815260206004820152600d60248201526c2320a629a2afaa2924a3a3a2a960991b6044820152606401610c3a565b6000806000611feb8c8686613f12565b91945092509050600384600481111561200657612006615411565b036120735787608001516120265780896001600160401b03161015612034565b80896001600160401b031611155b9550856120735760405162461bcd60e51b815260206004820152600d60248201526c2320a629a2afaa2924a3a3a2a960991b6044820152606401610c3a565b8a600381111561208557612085615411565b604080516001600160401b038c16815260208101849052908101859052606081018490528d907fe67823c5c7b61d690bab4b46031d192b68f898b47bdf7daffbddff8e24aaf9bd9060800160405180910390a3505050505050505050505050565b6000546001600160a01b0316331461212d5760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa0a226a4a760b11b6044820152606401610c3a565b600082815260086020526040808220805460ff19168415159081179091559051909184917f996384f9c771a575699aadc5e543fb849613b350a1b29584a1ecca98d2cfc1709190a35050565b601160205282600052604060002060205281600052604060002081815481106121a157600080fd5b6000918252602090912001546001600160a01b0316925083915050565b6121cc6064620186a0615911565b81565b6004805460405163731aa5f960e01b815233928101929092526001600160a01b03169063731aa5f990602401602060405180830381865afa158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c9190615703565b6122585760405162461bcd60e51b8152600401610c3a90615720565b6000858152600d602052604090206002600182015460ff16600581111561228157612281615411565b1461229e5760405162461bcd60e51b8152600401610c3a9061596b565b6000868152600c6020908152604080832054600160a01b900461ffff168352600890915290205460ff16156122e55760405162461bcd60e51b8152600401610c3a90615748565b61232781600101600d9054906101000a900460ff16866001600160401b0316866001600160401b0316866001600160401b0316866001600160401b0316613164565b60018101805468ffffffffffffffff001916610100426001600160401b0390811691909102919091179091556000878152600e6020908152604080832080546001600160801b0316600160801b8987169081026001600160c01b031691909117600160c01b898816908102919091178355600f85529483902080548c88166001600160801b03199091168117600160401b988d169889021782558451928352948201959095529182019290925260608101939093529188907f098a3c0f7acdf2c147440d705e162d395db886273731a238b250793cde346d859060800160405180910390a25050505050505050565b6004546001600160a01b0316331461245c5760405162461bcd60e51b815260206004820152600960248201526821526567697374727960b81b6044820152606401610c3a565b6001600160a01b038381166000908152600a602052604090205416156124c45760405162461bcd60e51b815260206004820152601760248201527f41535345545f414c52454144595f535550504f525445440000000000000000006044820152606401610c3a565b6001600160a01b038084166000818152600a6020908152604080832080548689166001600160a01b03199182168117909255600b9093528184208054968816969093168617909255519092917fe34fb4592f12d191480ae66f1051ba82ee53c518b07f632579da8d40a74c77c891a4505050565b60408051606095861b6bffffffffffffffffffffffff199081166020808401919091529590961b909516603486015260f09290921b6001600160f01b031916604885015260e01b6001600160e01b031916604a8401528051602e818503018152604e9093019052815191012090565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa1580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190615703565b6126305760405162461bcd60e51b8152600401610c3a90615887565b6000848152600d60209081526040808320600e8352818420600c845293829020825160808101845281546001600160a01b038082168352600160a01b820461ffff1696830196909652600160b01b900463ffffffff169381019390935260010154909216606082015281549192916126ba5760405162461bcd60e51b8152600401610c3a90615941565b6003600184015460ff1660058111156126d5576126d5615411565b146126f25760405162461bcd60e51b8152600401610c3a9061596b565b80516001600160a01b039081166000908152600b60205260408120549091169080600189600281111561272757612727615411565b036129e25760006127c8846001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561276f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612793919061586e565b6001890154600160701b81046001600160401b031690600160481b810463ffffffff16908d90600160681b900460ff16614116565b9050886001600160401b0316816001600160401b03161461281d5760405162461bcd60e51b815260206004820152600f60248201526e4241445f4649454c445f56414c554560881b6044820152606401610c3a565b85546001600160401b03600160801b90910481169082160361286b5760405162461bcd60e51b8152602060048201526007602482015266053414d455f54560cc1b6044820152606401610c3a565b8092508560000160189054906101000a90046001600160401b03169150428660000160006101000a8154816001600160401b0302191690836001600160401b03160217905550836001600160a01b0316633cdc20f88c876060015188602001518b600001548c60010160099054906101000a900463ffffffff168d600101600d9054906101000a900460ff168e600101600e9054906101000a90046001600160401b03168e60000160109054906101000a90046001600160401b03168c6040518a63ffffffff1660e01b81526004016129aa999897969594939291909889526001600160a01b0397909716602089015261ffff959095166040880152606087019390935263ffffffff919091166080860152151560a08501526001600160401b0390811660c085015290811660e0840152166101008201526101200190565b600060405180830381600087803b1580156129c457600080fd5b505af11580156129d8573d6000803e3d6000fd5b5050505050612b73565b60028960028111156129f6576129f6615411565b0361169a576000612a97846001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a62919061586e565b6001890154600160701b81046001600160401b031690600160481b810463ffffffff16908d90600160681b900460ff166141e8565b9050886001600160401b0316816001600160401b031614612aec5760405162461bcd60e51b815260206004820152600f60248201526e4241445f4649454c445f56414c554560881b6044820152606401610c3a565b85546001600160401b03600160c01b909104811690821603612b3a5760405162461bcd60e51b815260206004820152600760248201526614d0535157d4d360ca1b6044820152606401610c3a565b8554426001600160401b03908116600160401b026fffffffffffffffff0000000000000000198316178855600160801b90910416925090505b6001860154612b9f90600160681b900460ff166001600160401b03898116908190868116908616613164565b84546001600160401b03838116600160801b0267ffffffffffffffff60801b19918416600160c01b02919091166001600160801b0390921691909117178555886002811115612bf057612bf0615411565b846020015161ffff168b7f90bbb7e2b715065bd66ba75a34fca9b65694d5e75327dd0873a5e3e68837766789600101600d9054906101000a900460ff168c604051612c5092919091151582526001600160401b0316602082015260400190565b60405180910390a450505050505050505050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015612cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd19190615703565b612ced5760405162461bcd60e51b8152600401610c3a90615887565b6000838152600f6020908152604091829020825160808101845290546001600160401b038082168352600160401b82048116938301849052600160801b8204811694830194909452600160c01b90049092166060830152612d605760405162461bcd60e51b8152600401610c3a90615941565b80516001600160401b0380841691161180612d905750816001600160401b031681602001516001600160401b0316105b15612da657612da130856001613d2f565b612e0f565b6000806000612dc087866001600160401b03166004613f12565b6040805182815260208101859052908101839052929550909350915087907f9912c2c8197504aea5a1b52b98eeae3f4aecabe190feebc292455c355d4297cb9060600160405180910390a25050505b50505050565b6004805460405163731aa5f960e01b815233928101929092526001600160a01b03169063731aa5f990602401602060405180830381865afa158015612e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e829190615703565b612e9e5760405162461bcd60e51b8152600401610c3a90615720565b6000838152600d602052604090208054612eca5760405162461bcd60e51b8152600401610c3a90615941565b6003600182015460ff166005811115612ee557612ee5615411565b14612f025760405162461bcd60e51b8152600401610c3a9061596b565b6001810180546001600160401b034281166101000268ffffffffffffffffff19909216919091176004179091556000858152600f60209081526040918290208054868516600160401b81026001600160801b03199092169589169586179190911782558351948552918401919091529186917fb7bb5d6820a30953d2858e9c448319c4cebbc70c347961e25f1adfff46566689910160405180910390a25050505050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015612fef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130139190615703565b61302f5760405162461bcd60e51b8152600401610c3a90615887565b6111fb836001848461369b565b6040805160a081018252600080825260208083018290528284018290526060830182905260808301829052848252600d8152838220845160e0810190955280548552600181015493949293909183019060ff1660058111156130a0576130a0615411565b60058111156130b1576130b1615411565b8152600191909101546001600160401b036101008204811660208085019190915263ffffffff600160481b8404811660408087019190915260ff600160681b8604161515606080880191909152600160701b86048516608080890191909152600160b01b909604831660a09788015287518a52878101519092168984015294860151831690880152938201511515868401526000968752600e909352942054600160801b90041692820192909252919050565b828411156131a65760405162461bcd60e51b815260206004820152600f60248201526e4d494e5f4d41585f5245564552534560881b6044820152606401610c3a565b8115806131bf5750846131bb578382106131bf565b8282115b6131f65760405162461bcd60e51b8152602060048201526008602482015267057524f4e475f54560c41b6044820152606401610c3a565b80158061320f57508461320b5782811161320f565b8381105b611c0d5760405162461bcd60e51b815260206004820152600860248201526715d493d391d7d4d360c21b6044820152606401610c3a565b600080613252846113e4565b905061326085858584612538565b6000818152600c60205260408120805492945091600160b01b900463ffffffff1690036133ae578054600180830180546001600160a01b0319166001600160a01b038981169182179092559089166001600160b01b031990931692909217600160a01b61ffff8816021763ffffffff60b01b1916600160b01b63ffffffff86169081029190911784556000838152601560209081526040808320805463ffffffff19169094179093556016815282822080549485018155808352818320909401889055925493815260178352818120878252909252902055827f487ea6416487448c3ce943d750c8f67a275e4d8f26ac4093803bf63354b7006f826040516133a5919081546001600160a01b03808216835260a082901c61ffff16602084015260b09190911c63ffffffff166040830152600190920154909116606082015260800190565b60405180910390a25b50935093915050565b80156111fb576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015613404573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613428919061586e565b905061343f6001600160a01b0385168430856142a5565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa919061586e565b9050826134b78383615990565b14611c0d5760405162461bcd60e51b815260206004820152601560248201527411125117d393d517d49150d152559157d1561050d5605a1b6044820152606401610c3a565b6001600160a01b03811660009081526016602052604090205460010361134b57601380546001810182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b039390931692831790555460009182526014602052604090912055565b6001600160a01b0383166000908152600960205260408120818460038111156135a3576135a3615411565b60038111156135b4576135b4615411565b8152602001908152602001600020549050600060096000866001600160a01b03166001600160a01b03168152602001908152602001600020600085600381111561360057613600615411565b600381111561361157613611615411565b81526020810191909152604001600020556136366001600160a01b038516838361430c565b816001600160a01b031683600381111561365257613652615411565b856001600160a01b03167f0e80b333c403be7cb491b3ba7f29fe30014c594adbcbec04272291b2f72f6e6a8460405161368d91815260200190565b60405180910390a450505050565b6000848152600f60209081526040808320815160808101835290546001600160401b038082168352600160401b8204811683860152600160801b8204811683850152600160c01b909104166060820152878452600d8352818420825160e0810190935280548352600181015491949390919083019060ff16600581111561372457613724615411565b600581111561373557613735615411565b8152600191909101546001600160401b0361010082048116602084015263ffffffff600160481b83048116604085015260ff600160681b84041615156060850152600160701b83049091166080840152600160b01b9091041660a09091015280519091506137b55760405162461bcd60e51b8152600401610c3a90615941565b6000868152600c60209081526040808320815160808101835281546001600160a01b038082168352600160a01b820461ffff16838701819052600160b01b90920463ffffffff1683860152600190930154909216606082015290845260089092529091205460ff161561383a5760405162461bcd60e51b8152600401610c3a90615748565b85600581111561384c5761384c615411565b8260200151600581111561386257613862615411565b1461387f5760405162461bcd60e51b8152600401610c3a9061596b565b600186600581111561389357613893615411565b036139375782516001600160401b03808716911611806138c85750846001600160401b031683602001516001600160401b0316105b15613932576040516001600160401b038616815287907f82c058420d58fdfcaa301ef645c860145096603267b7b7ac02831312ac2ab4479060200160405180910390a261392a8782600001518360600151856000015186606001518930613e40565b505050612e0f565b6139bd565b600286600581111561394b5761394b615411565b0361169a5782516001600160401b038087169116118015906139835750846001600160401b031683602001516001600160401b031610155b6139325760405162461bcd60e51b815260206004820152600b60248201526a50524943455f52414e474560a81b6044820152606401610c3a565b80516001600160a01b039081166000908152600b60205260408120546060850151608086015191909316926139f7918b9185918b8a61433d565b9050816001600160a01b03166352713f678a85606001518660200151886000015189606001518a6080015188604001518f6040518963ffffffff1660e01b8152600401613a9d9897969594939291909788526001600160a01b0396909616602088015261ffff949094166040870152606086019290925263ffffffff166080850152151560a08401526001600160401b0390811660c08401521660e08201526101000190565b60408051808303816000875af1925050508015613ad7575060408051601f3d908101601f19168201909252613ad4918101906159a3565b60015b613bdb57613ae36159c7565b806308c379a003613b1c5750613af76159e2565b80613b025750613b1e565b8060405162461bcd60e51b8152600401610c3a919061526f565b505b3d808015613b48576040519150601f19603f3d011682016040523d82523d6000602084013e613b4d565b606091505b50632eb752bf60e21b613b5f82615a6b565b6001600160e01b0319160361038e57602481015160448201516040518c907ff2c847d05971bf83dd347e0732c1ef893111318fb2540f5fe6f9783cb8d6ae5b90613bac9085908590615aa2565b60405180910390a2613bd38c876000015188606001518a600001518b606001518e30613e40565b505050613d24565b60008b8152600d602090815260408083206001810180546001600160401b038f16600160701b0267ffffffffffffffff60701b19909116179055895160109093529220558651613c2c908490615990565b8155600180820180546001600160401b0342166101000268ffffffffffffffffff199091161760031790558651613c6f918e9190613c6a8688615990565b6146c0565b85516001600160a01b038082166000908152600a6020526040902054613c9792911684614774565b60008c8152600f60205260408082209190915584810151606086015191518e927fdd0164525ce1bb6897fbd7000a7d93633016a05f498d94903ca1fcc7911cdf8192613d18928f9290899089906001600160401b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b60405180910390a25050505b505050505050505050565b6000828152600d6020526040902054613d5a5760405162461bcd60e51b8152600401610c3a90615941565b6000828152600f60205260408120556001816001811115613d7d57613d7d615411565b03611bb35760046000838152600d602052604090206001015460ff166005811115613daa57613daa615411565b14613dc75760405162461bcd60e51b8152600401610c3a9061596b565b6000828152600d6020908152604080832060010180546001600160401b0342166101000268ffffffffffffffffff19909116176003179055519182526001600160a01b0385169184917f2cb817145129b5c52a6dc17e0605285c54d9c258fbf0a21e78bfff4e00813333910160405180910390a3505050565b6000878152600d6020908152604080832083815560010180546001600160d01b0319169055600f9091528120819055613e88613e828663ffffffff871661478e565b846147a6565b9050613e9788886003846146c0565b613ea0866147b6565b613eaa8689614a26565b6000613eb68287615990565b9050613ec3888883614774565b826001600160a01b0316897f0732bc6c415e7a220efee5f866e1e91a1335745b97373898ffecfddbc708a3e784604051613eff91815260200190565b60405180910390a3505050505050505050565b6000838152600c60209081526040808320815160808101835281546001600160a01b038082168352600160a01b820461ffff1695830195909552600160b01b900463ffffffff16928101929092526001015490911660608201528190819081613f7a8861303c565b8051909150613f9b5760405162461bcd60e51b8152600401610c3a90615941565b600080600080613fae8c87878e8e614b51565b93509350935093508460000151831115614030578451600090620186a0613fd58287615990565b613fdf91906158e4565b613fe99190615911565b905060075481111561402e5760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d41493d1925560921b6044820152606401610c3a565b505b819750829850809650846000015184111561408d5760405162461bcd60e51b815260206004820152601e60248201527f434c4f53455f4645455f4c41524745525f5448414e5f504f534954494f4e00006044820152606401610c3a565b61409e8c87600001516002876146c0565b6140ab86606001516147b6565b6140b986606001518d614a26565b60008c8152600d6020908152604080832083815560010180546001600160d01b0319169055600e825280832083905560109091528120556060860151865186516141079291908c9088614c03565b50505050505093509350939050565b60006001600160401b038316158061414057508560070b61413a8787868689614d6c565b60070b12155b156141dc576000620186a0856001600160401b03166064896001600160401b0316896001600160401b031661417591906158e4565b61417f91906158e4565b6141899190615911565b6141939190615911565b9050826141ca57856001600160401b0316816001600160401b031611156141bb5760006141d4565b6141c58187615ac0565b6141d4565b6141d48187615ae0565b9150506141df565b50815b95945050505050565b60006001600160401b038316158061421d575060065461420a90600019615b00565b6142178787868689614d6c565b60070b13155b156141dc576000620186a0856001600160401b03166064600654896001600160401b031661424b91906158e4565b61425591906158e4565b61425f9190615911565b6142699190615911565b90508261427a576141c58187615ae0565b856001600160401b0316816001600160401b0316111561429b5760006141d4565b6141d48187615ac0565b6040516001600160a01b038481166024830152838116604483015260648201839052612e0f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050614df8565b6040516001600160a01b038381166024830152604482018390526111fb91859182169063a9059cbb906064016142da565b6040805160808101825260008082526020820181905291810182905260608101919091526000866001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c5919061586e565b6000898152600e6020908152604091829020825160808101845290546001600160401b038082168352600160401b8204811693830193909352600160801b81048316938201849052600160c01b9004909116606082015293509091501580614438575060408301516001600160401b0316155b6144845760405162461bcd60e51b815260206004820152601760248201527f4d554c5449504c455f54505f444546494e4954494f4e530000000000000000006044820152606401610c3a565b60608201516001600160401b031615806144a9575060608301516001600160401b0316155b6144f55760405162461bcd60e51b815260206004820152601760248201527f4d554c5449504c455f534c5f444546494e4954494f4e530000000000000000006044820152606401610c3a565b60408301516001600160401b03161561456f57600061451f8585604001518963ffffffff16614e69565b90508561455557846001600160401b0316816001600160401b03161061454657600061455f565b6145508186615ac0565b61455f565b61455f8186615ae0565b6001600160401b03166040840152505b60608301516001600160401b0316156145e95760006145998585606001518963ffffffff16614e69565b9050856145af576145aa8186615ae0565b6145d9565b846001600160401b0316816001600160401b0316106145cf5760006145d9565b6145d98186615ac0565b6001600160401b03166060840152505b61460081858863ffffffff16856040015189614116565b6001600160401b03908116604084015242168252606082015161462f908290869063ffffffff8a1690896141e8565b6001600160401b0390811660608401908152428216602080860191825260009b8c52600e905260409a8b90208551815492519c87015193518516600160c01b026001600160c01b03948616600160801b02949094166001600160801b039d8616600160401b026001600160801b03199094169190951617919091179a909a1691909117179097559695505050505050565b8015612e0f576001600160a01b038316600090815260096020526040812082918460038111156146f2576146f2615411565b600381111561470357614703615411565b815260200190815260200160002060008282546147209190615b30565b90915550829050600381111561473857614738615411565b836001600160a01b0316857f52aab89a61b38ba21feecda2012e9c20aec817e5d709d0633c3fd693bb949cbb8460405161368d91815260200190565b80156111fb576111fb6001600160a01b038416838361430c565b6000606461479c83856158e4565b6114779190615911565b6000620186a061479c83856158e4565b6001600160a01b03811660009081526016602052604090205460010361134b576001600160a01b038116600090815260146020526040812054908190036148405760408051600080825260208201526001600160a01b038416917fd206397c5bb871d309f7602ac869a71536b264e19e25714421d6456b6b5008d991015b60405180910390a25050565b601361484d600183615990565b8154811061485d5761485d615b43565b6000918252602090912001546001600160a01b03838116911614614908576001600160a01b0382166000818152601460205260408120557fd206397c5bb871d309f7602ac869a71536b264e19e25714421d6456b6b5008d98260136148c3600183615990565b815481106148d3576148d3615b43565b60009182526020909120015460405161483492916001600160a01b0316909182526001600160a01b0316602082015260400190565b601354600110156149d6576013805461492390600190615990565b8154811061493357614933615b43565b6000918252602090912001546001600160a01b03166013614955600184615990565b8154811061496557614965615b43565b6000918252602082200180546001600160a01b0319166001600160a01b039390931692909217909155819060149060136149a0600185615990565b815481106149b0576149b0615b43565b60009182526020808320909101546001600160a01b031683528201929092526040019020555b6001600160a01b0382166000908152601460205260408120556013805480614a0057614a00615b59565b600082815260209020810160001990810180546001600160a01b03191690550190555050565b6001600160a01b038216600090815260176020908152604080832084845290915290205480156111fb576001600160a01b038316600090815260166020526040812090614a74600184615990565b8254909150614a8590600190615990565b811015614b015781546000908390614a9f90600190615990565b81548110614aaf57614aaf615b43565b9060005260206000200154905080838381548110614acf57614acf615b43565b60009182526020808320909101929092556001600160a01b038816815260178252604080822093825292909152208390555b81805480614b1157614b11615b59565b6000828152602080822083016000199081018390559092019092556001600160a01b03871682526017815260408083208784529091528120555050505050565b83516001600160a01b039081166000908152600b60209081526040808320546060890151928901519151630f1a62d160e31b8152939485948594859493909216926378d3168892614bad928e92908d908d908d90600401615b6f565b6080604051808303816000875af1158015614bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bf09190615bc6565b929c919b50995090975095505050505050565b6001600160a01b038085166000908152600a602052604081205490911690838510614cac57614c328385615990565b90506000614c408287615990565b6040516321d4911360e01b81526001600160a01b038a8116600483015260248201839052919250908416906321d4911390604401600060405180830381600087803b158015614c8e57600080fd5b505af1158015614ca2573d6000803e3d6000fd5b5050505050614d58565b50836000614cba8286615990565b905083811115614cdd57614cd88784614cd38785615990565b614774565b614d56565b6001600160a01b0383166321d4911330614cf78488615990565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015614d3d57600080fd5b505af1158015614d51573d6000803e3d6000fd5b505050505b505b614d63868883614774565b50505050505050565b6000858184614d8457614d7f8688615bfc565b614d8e565b614d8e8787615bfc565b905060008460070b620186a08360070b614da89190615b00565b614db29190615b00565b90506000600789900b614dc6606484615c2b565b614dd09190615c2b565b90508094508360070b8560070b13614de85784614dea565b835b9a9950505050505050505050565b600080602060008451602086016000885af180614e1b576040513d6000823e3d81fd5b50506000513d91508115614e33578060011415614e40565b6001600160a01b0384163b155b15612e0f57604051635274afe760e01b81526001600160a01b0385166004820152602401610c3a565b600080826001600160401b0316620186a06064866001600160401b0316886001600160401b0316614e9a91906158e4565b614ea491906158e4565b614eae9190615911565b6141df9190615911565b6003811061134b57600080fd5b606081018181106001600160401b0382111715614ef257634e487b7160e01b600052604160045260246000fd5b60405250565b61012081016001600160401b0381118282101715614ef257634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715614f5957634e487b7160e01b600052604160045260246000fd5b6040525050565b604051614f6c81614ef8565b90565b6001600160a01b038116811461134b57600080fd5b803561ffff81168114614f9657600080fd5b919050565b801515811461134b57600080fd5b8035614f9681614f9b565b803563ffffffff81168114614f9657600080fd5b80356001600160401b0381168114614f9657600080fd5b6000806000808486036101c0811215614ff757600080fd5b853561500281614eb8565b94506060601f198201121561501657600080fd5b60405161502281614ec5565b602087013561503081614f6f565b815261503e60408801614f84565b6020820152606087013561505181614f6f565b60408201529350610120607f19820181131561506c57600080fd5b615074614f60565b915061508260808801614fa9565b825260a0870135602083015261509a60c08801614fb4565b60408301526150ab60e08801614fc8565b60608301526101006150be818901614fc8565b60808401526150ce828901614fc8565b60a08401526150e06101408901614fc8565b60c08401526150f26101608901614fc8565b60e08401526151046101808901614fc8565b908301525091506151186101a08601614fb4565b905092959194509250565b60006020828403121561513557600080fd5b813561147781614f6f565b60006020828403121561515257600080fd5b5035919050565b6004811061134b57600080fd5b60008060006060848603121561517b57600080fd5b833561518681614f6f565b9250602084013561519681615159565b915060408401356151a681614f6f565b809150509250925092565b6000806000606084860312156151c657600080fd5b833592506151d660208501614fc8565b9150604084013590509250925092565b600080604083850312156151f957600080fd5b823561520481615159565b946020939093013593505050565b6000806040838503121561522557600080fd5b823561523081614f6f565b9150602083013561524081615159565b809150509250929050565b60005b8381101561526657818101518382015260200161524e565b50506000910152565b602081526000825180602084015261528e81604085016020870161524b565b601f01601f19169190910160400192915050565b600080604083850312156152b557600080fd5b823561520481614f6f565b6020808252825182820181905260009190848201906040850190845b818110156152f8578351835292840192918401916001016152dc565b50909695505050505050565b60008060006060848603121561531957600080fd5b8335925060208401356002811061532f57600080fd5b929592945050506040919091013590565b60008060006060848603121561535557600080fd5b83359250602084013561532f81614eb8565b6020808252825182820181905260009190848201906040850190845b818110156152f85783516001600160a01b031683529284019291840191600101615383565b600080600080608085870312156153be57600080fd5b8435935060208501356153d081615159565b92506153de60408601614fc8565b915061511860608601614fc8565b600080604083850312156153ff57600080fd5b82359150602083013561524081614f9b565b634e487b7160e01b600052602160045260246000fd5b6006811061543757615437615411565b9052565b87815260e0810161544f6020830189615427565b6001600160401b03968716604083015263ffffffff958616606083015293151560808201529190941660a08201529290911660c09092019190915292915050565b6000806000606084860312156154a557600080fd5b83356154b081614f6f565b95602085013595506040909401359392505050565b60a081016154d38288615427565b6001600160401b0395909516602082015261ffff939093166040840152901515606083015263ffffffff16608090910152919050565b600080600080600060a0868803121561552157600080fd5b8535945061553160208701614fc8565b935061553f60408701614fc8565b925061554d60608701614fc8565b915061555b60808701614fc8565b90509295509295909350565b60008060006060848603121561557c57600080fd5b833561558781614f6f565b9250602084013561519681614f6f565b600080600080608085870312156155ad57600080fd5b84356155b881614f6f565b935060208501356155c881614f6f565b92506155d660408601614f84565b915061511860608601614fb4565b600080600080608085870312156155fa57600080fd5b8435935060208501356153d081614eb8565b60008060006060848603121561562157600080fd5b8335925061563160208501614fc8565b915061563f60408501614fc8565b90509250925092565b60008060006060848603121561565d57600080fd5b833561566881614f6f565b9250602084013561532f81614f6f565b8051825263ffffffff602082015116602083015260408101511515604083015260608101516001600160401b03808216606085015280608084015116608085015250505050565b60a08101611c8e8284615678565b606081016156db8286615427565b6001600160401b039390931660208201526001600160a01b0391909116604090910152919050565b60006020828403121561571557600080fd5b815161147781614f9b565b6020808252600e908201526d08551c9859195c9cd41bdc9d185b60921b604082015260600190565b6020808252600b908201526a1410525497d4105554d15160aa1b604082015260600190565b6101e0810161577c8288615427565b63ffffffff808716602084015260018060a01b0380875116604085015261ffff6020880151166060850152806040880151166080850152508451151560a0840152602085015160c08401528060408601511660e08401525060608401516101006157f0818501836001600160401b03169052565b60808601516001600160401b0390811661012086015260a0870151811661014086015260c0870151811661016086015260e087015181166101808601529501519094166101a083015263ffffffff929092166101c090910152949350505050565b60006020828403121561586357600080fd5b815161147781614f6f565b60006020828403121561588057600080fd5b5051919050565b60208082526009908201526821547269676765727360b81b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b63ffffffff8181168382160190808211156158dd576158dd6158aa565b5092915050565b8082028115828204841417611c8e57611c8e6158aa565b634e487b7160e01b600052601260045260246000fd5b600082615920576159206158fb565b500490565b6000825161593781846020870161524b565b9190910192915050565b60208082526010908201526f2727afa9aaa1a42fa827a9a4aa24a7a760811b604082015260600190565b6020808252600b908201526a57524f4e475f504841534560a81b604082015260600190565b81810381811115611c8e57611c8e6158aa565b600080604083850312156159b657600080fd5b505080516020909101519092909150565b600060033d1115614f6c5760046000803e5060005160e01c90565b600060443d10156159f05790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615a1f57505050505090565b8285019150815181811115615a375750505050505090565b843d8701016020828501011115615a515750505050505090565b615a6060208286010187614f26565b509095945050505050565b805160208201516001600160e01b03198082169291906004831015615a9a5780818460040360031b1b83161693505b505050919050565b6040810160128410615ab657615ab6615411565b9281526020015290565b6001600160401b038281168282160390808211156158dd576158dd6158aa565b6001600160401b038181168382160190808211156158dd576158dd6158aa565b80820260008212600160ff1b84141615615b1c57615b1c6158aa565b8181058314821517611c8e57611c8e6158aa565b80820180821115611c8e57611c8e6158aa565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b8681526001600160a01b038616602082015261ffff851660408201526101408101615b9d6060830186615678565b8361010083015260058310615bb457615bb4615411565b82610120830152979650505050505050565b60008060008060808587031215615bdc57600080fd5b505082516020840151604085015160609095015191969095509092509050565b600782810b9082900b03677fffffffffffffff198112677fffffffffffffff82131715611c8e57611c8e6158aa565b600082615c3a57615c3a6158fb565b600160ff1b821460001984141615615c5457615c546158aa565b50059056fea26469706673582212200017cff3e05517e4e014b901ae71b90fbffe8fbf395d4bab63441515ac24900064736f6c63430008180033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061038e5760003560e01c806382571409116101de578063b71f3cfe1161010f578063ece938cf116100ad578063f555f6971161007c578063f555f69714610aed578063f5f5ba7214610b0d578063f851a44014610b37578063f9b9484e14610b4a57600080fd5b8063ece938cf14610a5b578063ef6ecc5514610a64578063f2eb245e14610ac4578063f51f3fd314610ae457600080fd5b8063ddf474f1116100e9578063ddf474f1146109cd578063e640f33b14610a15578063eb48914014610a28578063ec7f8a3a14610a3b57600080fd5b8063b71f3cfe1461099c578063c07f9921146109a7578063ca3a3a82146109ba57600080fd5b806395be50501161017c578063a40d726811610156578063a40d726814610947578063aaf5eb681461095a578063acfd6b9214610969578063ad1f2b561461099457600080fd5b806395be5050146108a65780639ff69ffa14610921578063a2a25ea61461093457600080fd5b80638f7a8fb5116101b85780638f7a8fb5146107e257806390f24cac1461085d57806393a7f6a71461087057806394a1e6e51461089e57600080fd5b806382571409146107a657806386dc4975146107af5780638aa10435146107c257600080fd5b8063396f7b23116102c357806368f296a51161026157806376d901be1161023057806376d901be146107435780637b1039991461077657806380193b261461078957806380a7f3d41461079357600080fd5b806368f296a5146106c15780636e01af8d146106e7578063725b7d52146106fa57806374d8b78e1461071a57600080fd5b80634ebe5c331161029d5780634ebe5c33146105f35780635c60da1b14610606578063614d08f81461061957806366307a4f1461064657600080fd5b8063396f7b23146105ad5780633ad6f124146105c05780633b17a497146105d357600080fd5b80631ea9af6b1161033057806324b22a1f1161030a57806324b22a1f1461052c578063267822471461053f57806330d073d01461055257806338b903331461057d57600080fd5b80631ea9af6b146104e95780632457bc3a146104fc5780632485f3f11461050457600080fd5b8063135e563d1161036c578063135e563d1461048557806318fa4714146104985780631961aba0146104ad5780631d504dc6146104d657600080fd5b8063010570851461039357806303b90a87146103b9578063042e37c5146103fa575b600080fd5b6103a66103a1366004614fdf565b610bac565b6040519081526020015b60405180910390f35b6103e26103c7366004615123565b600b602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016103b0565b610449610408366004615140565b600c60205260009081526040902080546001909101546001600160a01b0380831692600160a01b810461ffff1692600160b01b90910463ffffffff16911684565b604080516001600160a01b03958616815261ffff909416602085015263ffffffff909216918301919091529190911660608201526080016103b0565b6103e2610493366004615140565b611107565b6104ab6104a6366004615166565b611131565b005b6103a66104bb366004615123565b6001600160a01b031660009081526016602052604090205490565b6104ab6104e4366004615123565b611200565b6104ab6104f73660046151b1565b61134e565b6013546103a6565b610517610512366004615123565b6113e4565b60405163ffffffff90911681526020016103b0565b6104ab61053a3660046151e6565b61147e565b6001546103e2906001600160a01b031681565b6103a6610560366004615212565b600960209081526000928352604080842090915290825290205481565b6105a0604051806040016040528060048152602001630c4c0c4d60e21b81525081565b6040516103b0919061526f565b6003546103e2906001600160a01b031681565b6103a66105ce3660046152a2565b61171d565b6105e66105e1366004615123565b61174e565b6040516103b091906152c0565b6104ab610601366004615304565b6117ba565b6002546103e2906001600160a01b031681565b6105a06040518060400160405280600e81526020016d54726164696e67466c6f6f72563160901b81525081565b61068e610654366004615140565b600e602052600090815260409020546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b604080516001600160401b03958616815293851660208501529184169183019190915290911660608201526080016103b0565b6105176106cf366004615123565b60156020526000908152604090205463ffffffff1681565b6104ab6106f5366004615340565b61187e565b61070d6107083660046152a2565b611c14565b6040516103b09190615367565b6103e2610728366004615123565b600a602052600090815260409020546001600160a01b031681565b610766610751366004615140565b60086020526000908152604090205460ff1681565b60405190151581526020016103b0565b6004546103e2906001600160a01b031681565b6103a6620186a081565b6104ab6107a13660046153a8565b611c94565b6103a660075481565b6104ab6107bd3660046153ec565b6120e6565b6040805180820190915260048152630c4c0c4d60e21b60208201526105a0565b61084a6107f0366004615140565b600d602052600090815260409020805460019091015460ff808216916001600160401b03610100820481169263ffffffff600160481b8404811693600160681b810490921692600160701b83041691600160b01b90041687565b6040516103b0979695949392919061543b565b6103e261086b366004615490565b612179565b61076661087e366004615123565b6001600160a01b039081166000908152600a602052604090205416151590565b6103a66121be565b6109106108b4366004615140565b6000908152600d6020818152604080842060010154600c835293205491905260ff8083169361010084046001600160401b031693600160a01b90930461ffff1692600160681b810490921691600160b01b900463ffffffff1690565b6040516103b09594939291906154c5565b6104ab61092f366004615509565b6121cf565b6104ab610942366004615567565b612416565b6103a6610955366004615597565b612538565b6103a6670de0b6b3a764000081565b6103a66109773660046152a2565b601760209081526000928352604080842090915290825290205481565b6103a6606481565b6103a6633b9aca0081565b6104ab6109b53660046155e4565b6125a7565b6104ab6109c836600461560c565b612c64565b61068e6109db366004615140565b600f602052600090815260409020546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b6104ab610a2336600461560c565b612e15565b6104ab610a363660046151b1565b612fa6565b6103a6610a49366004615123565b60146020526000908152604090205481565b6103a660055481565b610aa7610a72366004615648565b601260209081526000938452604080852082529284528284209052825290205463ffffffff8082169164010000000090041682565b6040805163ffffffff9384168152929091166020830152016103b0565b6103a6610ad2366004615140565b60106020526000908152604090205481565b6103a660065481565b610b00610afb366004615140565b61303c565b6040516103b091906156bf565b60408051808201909152600e81526d54726164696e67466c6f6f72563160901b60208201526105a0565b6000546103e2906001600160a01b031681565b610b9d610b58366004615140565b6000908152600d60209081526040808320600190810154600c90935292209091015460ff8216926101009092046001600160401b0316916001600160a01b0390911690565b6040516103b0939291906156cd565b6004805460405163731aa5f960e01b815233928101929092526000916001600160a01b039091169063731aa5f990602401602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e9190615703565b610c435760405162461bcd60e51b8152600401610c3a90615720565b60405180910390fd5b610c6b84604001516001600160a01b039081166000908152600a602052604090205416151590565b610cb75760405162461bcd60e51b815260206004820152601e60248201527f4e4f4e5f535550504f525445445f534554544c454d454e545f415353455400006044820152606401610c3a565b60208085015161ffff1660009081526008909152604090205460ff1615610cf05760405162461bcd60e51b8152600401610c3a90615748565b6001856002811115610d0457610d04615411565b1480610d2157506002856002811115610d1f57610d1f615411565b145b610d665760405162461bcd60e51b8152602060048201526016602482015275554e535550504f525445445f4f524445525f5459504560501b6044820152606401610c3a565b610dab836000015184606001516001600160401b031685608001516001600160401b03168660a001516001600160401b03168760c001516001600160401b0316613164565b60055484516001600160a01b031660009081526016602052604090205410610e0d5760405162461bcd60e51b815260206004820152601560248201527426a0ac2faa2920a222a9afa822a92faa2920a222a960591b6044820152606401610c3a565b6000610e26856040015186600001518760200151613246565b8092508193505050610e458560400151866000015186602001516133b7565b8451610e50906134fc565b6000828152600d60205260409020805415610e975760405162461bcd60e51b8152602060048201526007602482015266125117d554d15160ca1b6044820152606401610c3a565b600180820180548751604089015163ffffffff908116600160481b026cffffffff00000000000000000019921515600160681b0260ff60681b19928b16600160b01b02929092166cffffffff0000000000000000ff60681b1990941693909317171617905560208601518255600090886002811115610f1857610f18615411565b14610f24576002610f27565b60015b9050808260010160006101000a81548160ff02191690836005811115610f4f57610f4f615411565b0217905550428260010160016101000a8154816001600160401b0302191690836001600160401b031602179055506000600e600086815260200190815260200160002090508660a001518160000160106101000a8154816001600160401b0302191690836001600160401b031602179055508660c001518160000160186101000a8154816001600160401b0302191690836001600160401b031602179055506000600f6000878152602001908152602001600020905087606001518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555087608001518160000160086101000a8154816001600160401b0302191690836001600160401b031602179055508760e001518160000160106101000a8154816001600160401b0302191690836001600160401b031602179055508761010001518160000160186101000a8154816001600160401b0302191690836001600160401b03160217905550857f835de04f5a930b169d6564c8f1c5f91f89abd9ea026b7488c94452abb900cc7484878c8c8c6040516110f295949392919061576d565b60405180910390a25050505050949350505050565b6013818154811061111757600080fd5b6000918252602090912001546001600160a01b0316905081565b6004805460405163a8e36e5b60e01b81526001600160a01b038681169382019390935291169063a8e36e5b90602401602060405180830381865afa15801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a19190615851565b6001600160a01b0316336001600160a01b0316146111f05760405162461bcd60e51b815260206004820152600c60248201526b10a332b2b9a6b0b730b3b2b960a11b6044820152606401610c3a565b6111fb838383613578565b505050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561123e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112629190615851565b6001600160a01b0316336001600160a01b0316146112b15760405162461bcd60e51b815260206004820152600c60248201526b10b83937bc3c9730b236b4b760a11b6044820152606401610c3a565b806001600160a01b031663c1e803346040518163ffffffff1660e01b81526004016020604051808303816000875af11580156112f1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611315919061586e565b1561134b5760405162461bcd60e51b8152600401610c3a9060208082526004908201526319985a5b60e21b604082015260600190565b50565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015611397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bb9190615703565b6113d75760405162461bcd60e51b8152600401610c3a90615887565b6111fb836002848461369b565b6001600160a01b03811660009081526015602052604081205463ffffffff9081169081106114545760405162461bcd60e51b815260206004820152601760248201527f504f534954494f4e5f494e4445585f4f564552464c4f570000000000000000006044820152606401610c3a565b600b8163ffffffff16101561146c5750600b92915050565b6114778160016158c0565b9392505050565b6000546001600160a01b031633146114c55760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa0a226a4a760b11b6044820152606401610c3a565b600081116115065760405162461bcd60e51b815260206004820152600e60248201526d43414e4e4f545f42455f5a45524f60901b6044820152606401610c3a565b6060600183600381111561151c5761151c615411565b03611555575060408051808201909152601281527136b0bc2a3930b232b9a832b92a3930b232b960711b602082015260058290556116d0565b600283600381111561156957611569615411565b036115f857606461157e620186a060326158e4565b6115889190615911565b8210156115d15760405162461bcd60e51b81526020600482015260176024820152762a2920a222afa820a920a6afa922a9aa2924a1aa24a7a760491b6044820152606401610c3a565b506040805180820190915260068082526536b0bc29b62360d11b60208301528290556116d0565b600383600381111561160c5761160c615411565b0361169a5761161f620186a060026158e4565b8210156116685760405162461bcd60e51b81526020600482015260176024820152762a2920a222afa820a920a6afa922a9aa2924a1aa24a7a760491b6044820152606401610c3a565b5060408051808201909152601081526f36b0bc29b0b734ba3ca83937b334ba2360811b602082015260078290556116d0565b60405162461bcd60e51b815260206004820152600b60248201526a155394d5541413d495115160aa1b6044820152606401610c3a565b806040516116de9190615925565b604051908190038120838252907f8cf3e35f6221b16e1670a3413180c9484bf5aa71787905909fa82a6a2662e9ab9060200160405180910390a2505050565b6016602052816000526040600020818154811061173957600080fd5b90600052602060002001600091509150505481565b6001600160a01b0381166000908152601660209081526040918290208054835181840281018401909452808452606093928301828280156117ae57602002820191906000526020600020905b81548152602001906001019080831161179a575b50505050509050919050565b6004805460405163419a519360e01b815233928101929092526001600160a01b03169063419a519390602401602060405180830381865afa158015611803573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118279190615703565b6118735760405162461bcd60e51b815260206004820152601a60248201527f212854726164657273506f7274616c7c7c5472696767657273290000000000006044820152606401610c3a565b6111fb338484613d2f565b6004805460405163419a519360e01b815233928101929092526001600160a01b03169063419a519390602401602060405180830381865afa1580156118c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118eb9190615703565b6119375760405162461bcd60e51b815260206004820152601a60248201527f212854726164657273506f7274616c7c7c5472696767657273290000000000006044820152606401610c3a565b6119456064620186a0615911565b81111561198b5760405162461bcd60e51b81526020600482015260146024820152734645455f4652414354494f4e5f544f4f5f42494760601b6044820152606401610c3a565b6000838152600d60209081526040808320815160e08101909252805482526001810154919290919083019060ff1660058111156119ca576119ca615411565b60058111156119db576119db615411565b8152600191909101546001600160401b036101008204811660208085019190915263ffffffff600160481b8404811660408087019190915260ff600160681b86041615156060870152600160701b85049093166080860152600160b01b90930490921660a0909301929092526000878152600d9091522054909150611a725760405162461bcd60e51b8152600401610c3a90615941565b6000848152600c6020908152604091829020825160808101845281546001600160a01b038082168352600160a01b820461ffff1694830194909452600160b01b900463ffffffff16938101939093526001908101549091166060830152846002811115611ae157611ae1615411565b03611b4357600182602001516005811115611afe57611afe615411565b14611b3e5760405162461bcd60e51b815260206004820152601060248201526f2727aa2fa6a0a925a2aa2fa7a92222a960811b6044820152606401610c3a565b611bee565b6002846002811115611b5757611b57615411565b03611bb357600282602001516005811115611b7457611b74615411565b14611b3e5760405162461bcd60e51b815260206004820152600f60248201526e2727aa2fa624a6a4aa2fa7a92222a960891b6044820152606401610c3a565b60405162461bcd60e51b815260206004820152601060248201526f57524f4e475f4f524445525f5459504560801b6044820152606401610c3a565b611c0d8582600001518360600151856000015186606001518833613e40565b5050505050565b6001600160a01b0382166000908152601160209081526040808320848452825291829020805483518184028101840190945280845260609392830182828015611c8657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c68575b505050505090505b92915050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015611cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d019190615703565b611d1d5760405162461bcd60e51b8152600401610c3a90615887565b6000848152600d60209081526040808320815160e08101909252805482526001810154919290919083019060ff166005811115611d5c57611d5c615411565b6005811115611d6d57611d6d615411565b8152600191909101546001600160401b0361010082048116602084015263ffffffff600160481b83048116604085015260ff600160681b84041615156060850152600160701b83049091166080840152600160b01b9091041660a0909101528051909150611ded5760405162461bcd60e51b8152600401610c3a90615941565b6000858152600e60209081526040808320815160808101835290546001600160401b038082168352600160401b8204811694830194909452600160801b8104841692820192909252600160c01b90910490911660608201529080806002886003811115611e5c57611e5c615411565b03611eb9578460800151611e895783606001516001600160401b0316866001600160401b03161015611ea4565b83606001516001600160401b0316866001600160401b031611155b925050506001600160401b0384166002611f9e565b6001886003811115611ecd57611ecd615411565b03611f30578460800151611efa5783604001516001600160401b0316866001600160401b03161115611f15565b83604001516001600160401b0316866001600160401b031610155b925083604001516001600160401b0316915060019050611f9e565b6003886003811115611f4457611f44615411565b03611f60575060019150506001600160401b0384166003611f9e565b60405162461bcd60e51b81526020600482015260136024820152722ba927a723afa624a6a4aa2faa2924a3a3a2a960691b6044820152606401610c3a565b82611fdb5760405162461bcd60e51b815260206004820152600d60248201526c2320a629a2afaa2924a3a3a2a960991b6044820152606401610c3a565b6000806000611feb8c8686613f12565b91945092509050600384600481111561200657612006615411565b036120735787608001516120265780896001600160401b03161015612034565b80896001600160401b031611155b9550856120735760405162461bcd60e51b815260206004820152600d60248201526c2320a629a2afaa2924a3a3a2a960991b6044820152606401610c3a565b8a600381111561208557612085615411565b604080516001600160401b038c16815260208101849052908101859052606081018490528d907fe67823c5c7b61d690bab4b46031d192b68f898b47bdf7daffbddff8e24aaf9bd9060800160405180910390a3505050505050505050505050565b6000546001600160a01b0316331461212d5760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa0a226a4a760b11b6044820152606401610c3a565b600082815260086020526040808220805460ff19168415159081179091559051909184917f996384f9c771a575699aadc5e543fb849613b350a1b29584a1ecca98d2cfc1709190a35050565b601160205282600052604060002060205281600052604060002081815481106121a157600080fd5b6000918252602090912001546001600160a01b0316925083915050565b6121cc6064620186a0615911565b81565b6004805460405163731aa5f960e01b815233928101929092526001600160a01b03169063731aa5f990602401602060405180830381865afa158015612218573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061223c9190615703565b6122585760405162461bcd60e51b8152600401610c3a90615720565b6000858152600d602052604090206002600182015460ff16600581111561228157612281615411565b1461229e5760405162461bcd60e51b8152600401610c3a9061596b565b6000868152600c6020908152604080832054600160a01b900461ffff168352600890915290205460ff16156122e55760405162461bcd60e51b8152600401610c3a90615748565b61232781600101600d9054906101000a900460ff16866001600160401b0316866001600160401b0316866001600160401b0316866001600160401b0316613164565b60018101805468ffffffffffffffff001916610100426001600160401b0390811691909102919091179091556000878152600e6020908152604080832080546001600160801b0316600160801b8987169081026001600160c01b031691909117600160c01b898816908102919091178355600f85529483902080548c88166001600160801b03199091168117600160401b988d169889021782558451928352948201959095529182019290925260608101939093529188907f098a3c0f7acdf2c147440d705e162d395db886273731a238b250793cde346d859060800160405180910390a25050505050505050565b6004546001600160a01b0316331461245c5760405162461bcd60e51b815260206004820152600960248201526821526567697374727960b81b6044820152606401610c3a565b6001600160a01b038381166000908152600a602052604090205416156124c45760405162461bcd60e51b815260206004820152601760248201527f41535345545f414c52454144595f535550504f525445440000000000000000006044820152606401610c3a565b6001600160a01b038084166000818152600a6020908152604080832080548689166001600160a01b03199182168117909255600b9093528184208054968816969093168617909255519092917fe34fb4592f12d191480ae66f1051ba82ee53c518b07f632579da8d40a74c77c891a4505050565b60408051606095861b6bffffffffffffffffffffffff199081166020808401919091529590961b909516603486015260f09290921b6001600160f01b031916604885015260e01b6001600160e01b031916604a8401528051602e818503018152604e9093019052815191012090565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa1580156125f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126149190615703565b6126305760405162461bcd60e51b8152600401610c3a90615887565b6000848152600d60209081526040808320600e8352818420600c845293829020825160808101845281546001600160a01b038082168352600160a01b820461ffff1696830196909652600160b01b900463ffffffff169381019390935260010154909216606082015281549192916126ba5760405162461bcd60e51b8152600401610c3a90615941565b6003600184015460ff1660058111156126d5576126d5615411565b146126f25760405162461bcd60e51b8152600401610c3a9061596b565b80516001600160a01b039081166000908152600b60205260408120549091169080600189600281111561272757612727615411565b036129e25760006127c8846001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561276f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612793919061586e565b6001890154600160701b81046001600160401b031690600160481b810463ffffffff16908d90600160681b900460ff16614116565b9050886001600160401b0316816001600160401b03161461281d5760405162461bcd60e51b815260206004820152600f60248201526e4241445f4649454c445f56414c554560881b6044820152606401610c3a565b85546001600160401b03600160801b90910481169082160361286b5760405162461bcd60e51b8152602060048201526007602482015266053414d455f54560cc1b6044820152606401610c3a565b8092508560000160189054906101000a90046001600160401b03169150428660000160006101000a8154816001600160401b0302191690836001600160401b03160217905550836001600160a01b0316633cdc20f88c876060015188602001518b600001548c60010160099054906101000a900463ffffffff168d600101600d9054906101000a900460ff168e600101600e9054906101000a90046001600160401b03168e60000160109054906101000a90046001600160401b03168c6040518a63ffffffff1660e01b81526004016129aa999897969594939291909889526001600160a01b0397909716602089015261ffff959095166040880152606087019390935263ffffffff919091166080860152151560a08501526001600160401b0390811660c085015290811660e0840152166101008201526101200190565b600060405180830381600087803b1580156129c457600080fd5b505af11580156129d8573d6000803e3d6000fd5b5050505050612b73565b60028960028111156129f6576129f6615411565b0361169a576000612a97846001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a62919061586e565b6001890154600160701b81046001600160401b031690600160481b810463ffffffff16908d90600160681b900460ff166141e8565b9050886001600160401b0316816001600160401b031614612aec5760405162461bcd60e51b815260206004820152600f60248201526e4241445f4649454c445f56414c554560881b6044820152606401610c3a565b85546001600160401b03600160c01b909104811690821603612b3a5760405162461bcd60e51b815260206004820152600760248201526614d0535157d4d360ca1b6044820152606401610c3a565b8554426001600160401b03908116600160401b026fffffffffffffffff0000000000000000198316178855600160801b90910416925090505b6001860154612b9f90600160681b900460ff166001600160401b03898116908190868116908616613164565b84546001600160401b03838116600160801b0267ffffffffffffffff60801b19918416600160c01b02919091166001600160801b0390921691909117178555886002811115612bf057612bf0615411565b846020015161ffff168b7f90bbb7e2b715065bd66ba75a34fca9b65694d5e75327dd0873a5e3e68837766789600101600d9054906101000a900460ff168c604051612c5092919091151582526001600160401b0316602082015260400190565b60405180910390a450505050505050505050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015612cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd19190615703565b612ced5760405162461bcd60e51b8152600401610c3a90615887565b6000838152600f6020908152604091829020825160808101845290546001600160401b038082168352600160401b82048116938301849052600160801b8204811694830194909452600160c01b90049092166060830152612d605760405162461bcd60e51b8152600401610c3a90615941565b80516001600160401b0380841691161180612d905750816001600160401b031681602001516001600160401b0316105b15612da657612da130856001613d2f565b612e0f565b6000806000612dc087866001600160401b03166004613f12565b6040805182815260208101859052908101839052929550909350915087907f9912c2c8197504aea5a1b52b98eeae3f4aecabe190feebc292455c355d4297cb9060600160405180910390a25050505b50505050565b6004805460405163731aa5f960e01b815233928101929092526001600160a01b03169063731aa5f990602401602060405180830381865afa158015612e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e829190615703565b612e9e5760405162461bcd60e51b8152600401610c3a90615720565b6000838152600d602052604090208054612eca5760405162461bcd60e51b8152600401610c3a90615941565b6003600182015460ff166005811115612ee557612ee5615411565b14612f025760405162461bcd60e51b8152600401610c3a9061596b565b6001810180546001600160401b034281166101000268ffffffffffffffffff19909216919091176004179091556000858152600f60209081526040918290208054868516600160401b81026001600160801b03199092169589169586179190911782558351948552918401919091529186917fb7bb5d6820a30953d2858e9c448319c4cebbc70c347961e25f1adfff46566689910160405180910390a25050505050565b6004805460405163a5a2ed3760e01b815233928101929092526001600160a01b03169063a5a2ed3790602401602060405180830381865afa158015612fef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130139190615703565b61302f5760405162461bcd60e51b8152600401610c3a90615887565b6111fb836001848461369b565b6040805160a081018252600080825260208083018290528284018290526060830182905260808301829052848252600d8152838220845160e0810190955280548552600181015493949293909183019060ff1660058111156130a0576130a0615411565b60058111156130b1576130b1615411565b8152600191909101546001600160401b036101008204811660208085019190915263ffffffff600160481b8404811660408087019190915260ff600160681b8604161515606080880191909152600160701b86048516608080890191909152600160b01b909604831660a09788015287518a52878101519092168984015294860151831690880152938201511515868401526000968752600e909352942054600160801b90041692820192909252919050565b828411156131a65760405162461bcd60e51b815260206004820152600f60248201526e4d494e5f4d41585f5245564552534560881b6044820152606401610c3a565b8115806131bf5750846131bb578382106131bf565b8282115b6131f65760405162461bcd60e51b8152602060048201526008602482015267057524f4e475f54560c41b6044820152606401610c3a565b80158061320f57508461320b5782811161320f565b8381105b611c0d5760405162461bcd60e51b815260206004820152600860248201526715d493d391d7d4d360c21b6044820152606401610c3a565b600080613252846113e4565b905061326085858584612538565b6000818152600c60205260408120805492945091600160b01b900463ffffffff1690036133ae578054600180830180546001600160a01b0319166001600160a01b038981169182179092559089166001600160b01b031990931692909217600160a01b61ffff8816021763ffffffff60b01b1916600160b01b63ffffffff86169081029190911784556000838152601560209081526040808320805463ffffffff19169094179093556016815282822080549485018155808352818320909401889055925493815260178352818120878252909252902055827f487ea6416487448c3ce943d750c8f67a275e4d8f26ac4093803bf63354b7006f826040516133a5919081546001600160a01b03808216835260a082901c61ffff16602084015260b09190911c63ffffffff166040830152600190920154909116606082015260800190565b60405180910390a25b50935093915050565b80156111fb576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015613404573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613428919061586e565b905061343f6001600160a01b0385168430856142a5565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa919061586e565b9050826134b78383615990565b14611c0d5760405162461bcd60e51b815260206004820152601560248201527411125117d393d517d49150d152559157d1561050d5605a1b6044820152606401610c3a565b6001600160a01b03811660009081526016602052604090205460010361134b57601380546001810182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b039390931692831790555460009182526014602052604090912055565b6001600160a01b0383166000908152600960205260408120818460038111156135a3576135a3615411565b60038111156135b4576135b4615411565b8152602001908152602001600020549050600060096000866001600160a01b03166001600160a01b03168152602001908152602001600020600085600381111561360057613600615411565b600381111561361157613611615411565b81526020810191909152604001600020556136366001600160a01b038516838361430c565b816001600160a01b031683600381111561365257613652615411565b856001600160a01b03167f0e80b333c403be7cb491b3ba7f29fe30014c594adbcbec04272291b2f72f6e6a8460405161368d91815260200190565b60405180910390a450505050565b6000848152600f60209081526040808320815160808101835290546001600160401b038082168352600160401b8204811683860152600160801b8204811683850152600160c01b909104166060820152878452600d8352818420825160e0810190935280548352600181015491949390919083019060ff16600581111561372457613724615411565b600581111561373557613735615411565b8152600191909101546001600160401b0361010082048116602084015263ffffffff600160481b83048116604085015260ff600160681b84041615156060850152600160701b83049091166080840152600160b01b9091041660a09091015280519091506137b55760405162461bcd60e51b8152600401610c3a90615941565b6000868152600c60209081526040808320815160808101835281546001600160a01b038082168352600160a01b820461ffff16838701819052600160b01b90920463ffffffff1683860152600190930154909216606082015290845260089092529091205460ff161561383a5760405162461bcd60e51b8152600401610c3a90615748565b85600581111561384c5761384c615411565b8260200151600581111561386257613862615411565b1461387f5760405162461bcd60e51b8152600401610c3a9061596b565b600186600581111561389357613893615411565b036139375782516001600160401b03808716911611806138c85750846001600160401b031683602001516001600160401b0316105b15613932576040516001600160401b038616815287907f82c058420d58fdfcaa301ef645c860145096603267b7b7ac02831312ac2ab4479060200160405180910390a261392a8782600001518360600151856000015186606001518930613e40565b505050612e0f565b6139bd565b600286600581111561394b5761394b615411565b0361169a5782516001600160401b038087169116118015906139835750846001600160401b031683602001516001600160401b031610155b6139325760405162461bcd60e51b815260206004820152600b60248201526a50524943455f52414e474560a81b6044820152606401610c3a565b80516001600160a01b039081166000908152600b60205260408120546060850151608086015191909316926139f7918b9185918b8a61433d565b9050816001600160a01b03166352713f678a85606001518660200151886000015189606001518a6080015188604001518f6040518963ffffffff1660e01b8152600401613a9d9897969594939291909788526001600160a01b0396909616602088015261ffff949094166040870152606086019290925263ffffffff166080850152151560a08401526001600160401b0390811660c08401521660e08201526101000190565b60408051808303816000875af1925050508015613ad7575060408051601f3d908101601f19168201909252613ad4918101906159a3565b60015b613bdb57613ae36159c7565b806308c379a003613b1c5750613af76159e2565b80613b025750613b1e565b8060405162461bcd60e51b8152600401610c3a919061526f565b505b3d808015613b48576040519150601f19603f3d011682016040523d82523d6000602084013e613b4d565b606091505b50632eb752bf60e21b613b5f82615a6b565b6001600160e01b0319160361038e57602481015160448201516040518c907ff2c847d05971bf83dd347e0732c1ef893111318fb2540f5fe6f9783cb8d6ae5b90613bac9085908590615aa2565b60405180910390a2613bd38c876000015188606001518a600001518b606001518e30613e40565b505050613d24565b60008b8152600d602090815260408083206001810180546001600160401b038f16600160701b0267ffffffffffffffff60701b19909116179055895160109093529220558651613c2c908490615990565b8155600180820180546001600160401b0342166101000268ffffffffffffffffff199091161760031790558651613c6f918e9190613c6a8688615990565b6146c0565b85516001600160a01b038082166000908152600a6020526040902054613c9792911684614774565b60008c8152600f60205260408082209190915584810151606086015191518e927fdd0164525ce1bb6897fbd7000a7d93633016a05f498d94903ca1fcc7911cdf8192613d18928f9290899089906001600160401b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b60405180910390a25050505b505050505050505050565b6000828152600d6020526040902054613d5a5760405162461bcd60e51b8152600401610c3a90615941565b6000828152600f60205260408120556001816001811115613d7d57613d7d615411565b03611bb35760046000838152600d602052604090206001015460ff166005811115613daa57613daa615411565b14613dc75760405162461bcd60e51b8152600401610c3a9061596b565b6000828152600d6020908152604080832060010180546001600160401b0342166101000268ffffffffffffffffff19909116176003179055519182526001600160a01b0385169184917f2cb817145129b5c52a6dc17e0605285c54d9c258fbf0a21e78bfff4e00813333910160405180910390a3505050565b6000878152600d6020908152604080832083815560010180546001600160d01b0319169055600f9091528120819055613e88613e828663ffffffff871661478e565b846147a6565b9050613e9788886003846146c0565b613ea0866147b6565b613eaa8689614a26565b6000613eb68287615990565b9050613ec3888883614774565b826001600160a01b0316897f0732bc6c415e7a220efee5f866e1e91a1335745b97373898ffecfddbc708a3e784604051613eff91815260200190565b60405180910390a3505050505050505050565b6000838152600c60209081526040808320815160808101835281546001600160a01b038082168352600160a01b820461ffff1695830195909552600160b01b900463ffffffff16928101929092526001015490911660608201528190819081613f7a8861303c565b8051909150613f9b5760405162461bcd60e51b8152600401610c3a90615941565b600080600080613fae8c87878e8e614b51565b93509350935093508460000151831115614030578451600090620186a0613fd58287615990565b613fdf91906158e4565b613fe99190615911565b905060075481111561402e5760405162461bcd60e51b815260206004820152600e60248201526d1253959053125117d41493d1925560921b6044820152606401610c3a565b505b819750829850809650846000015184111561408d5760405162461bcd60e51b815260206004820152601e60248201527f434c4f53455f4645455f4c41524745525f5448414e5f504f534954494f4e00006044820152606401610c3a565b61409e8c87600001516002876146c0565b6140ab86606001516147b6565b6140b986606001518d614a26565b60008c8152600d6020908152604080832083815560010180546001600160d01b0319169055600e825280832083905560109091528120556060860151865186516141079291908c9088614c03565b50505050505093509350939050565b60006001600160401b038316158061414057508560070b61413a8787868689614d6c565b60070b12155b156141dc576000620186a0856001600160401b03166064896001600160401b0316896001600160401b031661417591906158e4565b61417f91906158e4565b6141899190615911565b6141939190615911565b9050826141ca57856001600160401b0316816001600160401b031611156141bb5760006141d4565b6141c58187615ac0565b6141d4565b6141d48187615ae0565b9150506141df565b50815b95945050505050565b60006001600160401b038316158061421d575060065461420a90600019615b00565b6142178787868689614d6c565b60070b13155b156141dc576000620186a0856001600160401b03166064600654896001600160401b031661424b91906158e4565b61425591906158e4565b61425f9190615911565b6142699190615911565b90508261427a576141c58187615ae0565b856001600160401b0316816001600160401b0316111561429b5760006141d4565b6141d48187615ac0565b6040516001600160a01b038481166024830152838116604483015260648201839052612e0f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050614df8565b6040516001600160a01b038381166024830152604482018390526111fb91859182169063a9059cbb906064016142da565b6040805160808101825260008082526020820181905291810182905260608101919091526000866001600160a01b0316631cb92ed36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143c5919061586e565b6000898152600e6020908152604091829020825160808101845290546001600160401b038082168352600160401b8204811693830193909352600160801b81048316938201849052600160c01b9004909116606082015293509091501580614438575060408301516001600160401b0316155b6144845760405162461bcd60e51b815260206004820152601760248201527f4d554c5449504c455f54505f444546494e4954494f4e530000000000000000006044820152606401610c3a565b60608201516001600160401b031615806144a9575060608301516001600160401b0316155b6144f55760405162461bcd60e51b815260206004820152601760248201527f4d554c5449504c455f534c5f444546494e4954494f4e530000000000000000006044820152606401610c3a565b60408301516001600160401b03161561456f57600061451f8585604001518963ffffffff16614e69565b90508561455557846001600160401b0316816001600160401b03161061454657600061455f565b6145508186615ac0565b61455f565b61455f8186615ae0565b6001600160401b03166040840152505b60608301516001600160401b0316156145e95760006145998585606001518963ffffffff16614e69565b9050856145af576145aa8186615ae0565b6145d9565b846001600160401b0316816001600160401b0316106145cf5760006145d9565b6145d98186615ac0565b6001600160401b03166060840152505b61460081858863ffffffff16856040015189614116565b6001600160401b03908116604084015242168252606082015161462f908290869063ffffffff8a1690896141e8565b6001600160401b0390811660608401908152428216602080860191825260009b8c52600e905260409a8b90208551815492519c87015193518516600160c01b026001600160c01b03948616600160801b02949094166001600160801b039d8616600160401b026001600160801b03199094169190951617919091179a909a1691909117179097559695505050505050565b8015612e0f576001600160a01b038316600090815260096020526040812082918460038111156146f2576146f2615411565b600381111561470357614703615411565b815260200190815260200160002060008282546147209190615b30565b90915550829050600381111561473857614738615411565b836001600160a01b0316857f52aab89a61b38ba21feecda2012e9c20aec817e5d709d0633c3fd693bb949cbb8460405161368d91815260200190565b80156111fb576111fb6001600160a01b038416838361430c565b6000606461479c83856158e4565b6114779190615911565b6000620186a061479c83856158e4565b6001600160a01b03811660009081526016602052604090205460010361134b576001600160a01b038116600090815260146020526040812054908190036148405760408051600080825260208201526001600160a01b038416917fd206397c5bb871d309f7602ac869a71536b264e19e25714421d6456b6b5008d991015b60405180910390a25050565b601361484d600183615990565b8154811061485d5761485d615b43565b6000918252602090912001546001600160a01b03838116911614614908576001600160a01b0382166000818152601460205260408120557fd206397c5bb871d309f7602ac869a71536b264e19e25714421d6456b6b5008d98260136148c3600183615990565b815481106148d3576148d3615b43565b60009182526020909120015460405161483492916001600160a01b0316909182526001600160a01b0316602082015260400190565b601354600110156149d6576013805461492390600190615990565b8154811061493357614933615b43565b6000918252602090912001546001600160a01b03166013614955600184615990565b8154811061496557614965615b43565b6000918252602082200180546001600160a01b0319166001600160a01b039390931692909217909155819060149060136149a0600185615990565b815481106149b0576149b0615b43565b60009182526020808320909101546001600160a01b031683528201929092526040019020555b6001600160a01b0382166000908152601460205260408120556013805480614a0057614a00615b59565b600082815260209020810160001990810180546001600160a01b03191690550190555050565b6001600160a01b038216600090815260176020908152604080832084845290915290205480156111fb576001600160a01b038316600090815260166020526040812090614a74600184615990565b8254909150614a8590600190615990565b811015614b015781546000908390614a9f90600190615990565b81548110614aaf57614aaf615b43565b9060005260206000200154905080838381548110614acf57614acf615b43565b60009182526020808320909101929092556001600160a01b038816815260178252604080822093825292909152208390555b81805480614b1157614b11615b59565b6000828152602080822083016000199081018390559092019092556001600160a01b03871682526017815260408083208784529091528120555050505050565b83516001600160a01b039081166000908152600b60209081526040808320546060890151928901519151630f1a62d160e31b8152939485948594859493909216926378d3168892614bad928e92908d908d908d90600401615b6f565b6080604051808303816000875af1158015614bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bf09190615bc6565b929c919b50995090975095505050505050565b6001600160a01b038085166000908152600a602052604081205490911690838510614cac57614c328385615990565b90506000614c408287615990565b6040516321d4911360e01b81526001600160a01b038a8116600483015260248201839052919250908416906321d4911390604401600060405180830381600087803b158015614c8e57600080fd5b505af1158015614ca2573d6000803e3d6000fd5b5050505050614d58565b50836000614cba8286615990565b905083811115614cdd57614cd88784614cd38785615990565b614774565b614d56565b6001600160a01b0383166321d4911330614cf78488615990565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015614d3d57600080fd5b505af1158015614d51573d6000803e3d6000fd5b505050505b505b614d63868883614774565b50505050505050565b6000858184614d8457614d7f8688615bfc565b614d8e565b614d8e8787615bfc565b905060008460070b620186a08360070b614da89190615b00565b614db29190615b00565b90506000600789900b614dc6606484615c2b565b614dd09190615c2b565b90508094508360070b8560070b13614de85784614dea565b835b9a9950505050505050505050565b600080602060008451602086016000885af180614e1b576040513d6000823e3d81fd5b50506000513d91508115614e33578060011415614e40565b6001600160a01b0384163b155b15612e0f57604051635274afe760e01b81526001600160a01b0385166004820152602401610c3a565b600080826001600160401b0316620186a06064866001600160401b0316886001600160401b0316614e9a91906158e4565b614ea491906158e4565b614eae9190615911565b6141df9190615911565b6003811061134b57600080fd5b606081018181106001600160401b0382111715614ef257634e487b7160e01b600052604160045260246000fd5b60405250565b61012081016001600160401b0381118282101715614ef257634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b0381118282101715614f5957634e487b7160e01b600052604160045260246000fd5b6040525050565b604051614f6c81614ef8565b90565b6001600160a01b038116811461134b57600080fd5b803561ffff81168114614f9657600080fd5b919050565b801515811461134b57600080fd5b8035614f9681614f9b565b803563ffffffff81168114614f9657600080fd5b80356001600160401b0381168114614f9657600080fd5b6000806000808486036101c0811215614ff757600080fd5b853561500281614eb8565b94506060601f198201121561501657600080fd5b60405161502281614ec5565b602087013561503081614f6f565b815261503e60408801614f84565b6020820152606087013561505181614f6f565b60408201529350610120607f19820181131561506c57600080fd5b615074614f60565b915061508260808801614fa9565b825260a0870135602083015261509a60c08801614fb4565b60408301526150ab60e08801614fc8565b60608301526101006150be818901614fc8565b60808401526150ce828901614fc8565b60a08401526150e06101408901614fc8565b60c08401526150f26101608901614fc8565b60e08401526151046101808901614fc8565b908301525091506151186101a08601614fb4565b905092959194509250565b60006020828403121561513557600080fd5b813561147781614f6f565b60006020828403121561515257600080fd5b5035919050565b6004811061134b57600080fd5b60008060006060848603121561517b57600080fd5b833561518681614f6f565b9250602084013561519681615159565b915060408401356151a681614f6f565b809150509250925092565b6000806000606084860312156151c657600080fd5b833592506151d660208501614fc8565b9150604084013590509250925092565b600080604083850312156151f957600080fd5b823561520481615159565b946020939093013593505050565b6000806040838503121561522557600080fd5b823561523081614f6f565b9150602083013561524081615159565b809150509250929050565b60005b8381101561526657818101518382015260200161524e565b50506000910152565b602081526000825180602084015261528e81604085016020870161524b565b601f01601f19169190910160400192915050565b600080604083850312156152b557600080fd5b823561520481614f6f565b6020808252825182820181905260009190848201906040850190845b818110156152f8578351835292840192918401916001016152dc565b50909695505050505050565b60008060006060848603121561531957600080fd5b8335925060208401356002811061532f57600080fd5b929592945050506040919091013590565b60008060006060848603121561535557600080fd5b83359250602084013561532f81614eb8565b6020808252825182820181905260009190848201906040850190845b818110156152f85783516001600160a01b031683529284019291840191600101615383565b600080600080608085870312156153be57600080fd5b8435935060208501356153d081615159565b92506153de60408601614fc8565b915061511860608601614fc8565b600080604083850312156153ff57600080fd5b82359150602083013561524081614f9b565b634e487b7160e01b600052602160045260246000fd5b6006811061543757615437615411565b9052565b87815260e0810161544f6020830189615427565b6001600160401b03968716604083015263ffffffff958616606083015293151560808201529190941660a08201529290911660c09092019190915292915050565b6000806000606084860312156154a557600080fd5b83356154b081614f6f565b95602085013595506040909401359392505050565b60a081016154d38288615427565b6001600160401b0395909516602082015261ffff939093166040840152901515606083015263ffffffff16608090910152919050565b600080600080600060a0868803121561552157600080fd5b8535945061553160208701614fc8565b935061553f60408701614fc8565b925061554d60608701614fc8565b915061555b60808701614fc8565b90509295509295909350565b60008060006060848603121561557c57600080fd5b833561558781614f6f565b9250602084013561519681614f6f565b600080600080608085870312156155ad57600080fd5b84356155b881614f6f565b935060208501356155c881614f6f565b92506155d660408601614f84565b915061511860608601614fb4565b600080600080608085870312156155fa57600080fd5b8435935060208501356153d081614eb8565b60008060006060848603121561562157600080fd5b8335925061563160208501614fc8565b915061563f60408501614fc8565b90509250925092565b60008060006060848603121561565d57600080fd5b833561566881614f6f565b9250602084013561532f81614f6f565b8051825263ffffffff602082015116602083015260408101511515604083015260608101516001600160401b03808216606085015280608084015116608085015250505050565b60a08101611c8e8284615678565b606081016156db8286615427565b6001600160401b039390931660208201526001600160a01b0391909116604090910152919050565b60006020828403121561571557600080fd5b815161147781614f9b565b6020808252600e908201526d08551c9859195c9cd41bdc9d185b60921b604082015260600190565b6020808252600b908201526a1410525497d4105554d15160aa1b604082015260600190565b6101e0810161577c8288615427565b63ffffffff808716602084015260018060a01b0380875116604085015261ffff6020880151166060850152806040880151166080850152508451151560a0840152602085015160c08401528060408601511660e08401525060608401516101006157f0818501836001600160401b03169052565b60808601516001600160401b0390811661012086015260a0870151811661014086015260c0870151811661016086015260e087015181166101808601529501519094166101a083015263ffffffff929092166101c090910152949350505050565b60006020828403121561586357600080fd5b815161147781614f6f565b60006020828403121561588057600080fd5b5051919050565b60208082526009908201526821547269676765727360b81b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b63ffffffff8181168382160190808211156158dd576158dd6158aa565b5092915050565b8082028115828204841417611c8e57611c8e6158aa565b634e487b7160e01b600052601260045260246000fd5b600082615920576159206158fb565b500490565b6000825161593781846020870161524b565b9190910192915050565b60208082526010908201526f2727afa9aaa1a42fa827a9a4aa24a7a760811b604082015260600190565b6020808252600b908201526a57524f4e475f504841534560a81b604082015260600190565b81810381811115611c8e57611c8e6158aa565b600080604083850312156159b657600080fd5b505080516020909101519092909150565b600060033d1115614f6c5760046000803e5060005160e01c90565b600060443d10156159f05790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615a1f57505050505090565b8285019150815181811115615a375750505050505090565b843d8701016020828501011115615a515750505050505090565b615a6060208286010187614f26565b509095945050505050565b805160208201516001600160e01b03198082169291906004831015615a9a5780818460040360031b1b83161693505b505050919050565b6040810160128410615ab657615ab6615411565b9281526020015290565b6001600160401b038281168282160390808211156158dd576158dd6158aa565b6001600160401b038181168382160190808211156158dd576158dd6158aa565b80820260008212600160ff1b84141615615b1c57615b1c6158aa565b8181058314821517611c8e57611c8e6158aa565b80820180821115611c8e57611c8e6158aa565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b8681526001600160a01b038616602082015261ffff851660408201526101408101615b9d6060830186615678565b8361010083015260058310615bb457615bb4615411565b82610120830152979650505050505050565b60008060008060808587031215615bdc57600080fd5b505082516020840151604085015160609095015191969095509092509050565b600782810b9082900b03677fffffffffffffff198112677fffffffffffffff82131715611c8e57611c8e6158aa565b600082615c3a57615c3a6158fb565b600160ff1b821460001984141615615c5457615c546158aa565b50059056fea26469706673582212200017cff3e05517e4e014b901ae71b90fbffe8fbf395d4bab63441515ac24900064736f6c63430008180033

Block Transaction Gas Used Reward
view all blocks ##produced##

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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