v9.2.1 Update

Summary

  • 50% of the spread and price impact is now charged on trade opening and closing instead of 100% on trade opening

  • Existing trades don't pay any spread or impact on close (since they already paid in full on open), and they keep paying 100% spread when partial adding

  • Spread and price impact on close use the reverse direction as opening spread (makes price lower for longs and higher for shorts)

  • Price impact on close uses the opposite side depth and opposite side price impact OI (= cumulative vol now)

  • Price impact OI windows now use new cumulative volume logic (much shorter windows duration possible because more accurate, opening a long / closing a short uses/adds to long windows, opening a short / closing a long uses/adds to short windows, new cumulative factor which will be set to 1 to start with but can be used to adjust weight of price impact OI in price impact formula), we never remove any OI from windows anymore (logic much simpler, no longer need to move trade OI to current window for partials)

  • Closing price impact higher for short-term trades (depending on protection factor blocks duration and protection factor multiplier per pair), only when net PnL is positive

  • Liquidation price now takes into account the closing spread (not the price impact) for trades opened after v9.2 and uses new logic for the liquidation pnl % threshold (closer pnl % threshold as leverage increases, more aggressive for higher leverages similarly to MMR)

  • Existing trades aren't affected by the new liquidation threshold logic, liquidation parameters for trades are stored on opening so they can't change for an open trade even when a group's liquidation parameters are updated, however a trade's liquidation params are refreshed to current value when position size is increased using partials

  • New stop loss max distance is liqPnlThresholdP - 10% (eg. -70% PnL when trade liq pnl % threshold is -80%)

  • Added max slippage on close (market close, partial close, tp/sl) mechanism: by default 1% for all opened trades, can be adjusted after trade is open

  • Extracted cancel reason logic for limit/stop/tp/sl/liq callbacks into getters, will be used by EA-lookbacks to check ability to execute at past chain state

  • LIQ triggers no longer turned into SL triggers when SL is closer otherwise user could set very low max closing slippage and would never be able to be liquidated if price went past his SL and LIQ price, trigger bots will prioritize SL over LIQ when possible

Full Changelog

core/facets/GNSPairsStorage.sol (update)

  • Added initializeGroupLiquidationParams, setGroupLiquidationParams, getGroupLiquidationParams, and getPairLiquidationParams

core/facets/GNSPriceAggregator.sol (update)

  • getPrice now accepts _tradeId instead of _trader

core/facets/GNSPriceImpact.sol (update)

  • Added initializePairFactors, setProtectionCloseFactors, setProtectionCloseFactorBlocks, setCumulativeFactors, getPairFactors

  • Removed removePriceImpactOpenInterest, getTradeLastWindowOiUsd, getTradePriceImpactInfo

  • addPriceImpactOpenInterest now accepts _open argument

  • getTradePriceImpact now accepts _isPnlPositive, _open, _lastPosIncreaseBlock, and _contractsVersion arguments

core/facets/GNSTradingCallbacks.sol (update)

  • Added validateTriggerOpenOrderCallback and validateTriggerCloseOrderCallback getters

core/facets/GNSTradingInteractions.sol (update)

  • New updateMaxClosingSlippageP function

  • closeTradeMarket and decreasePositionSize now accept _expectedPrice argument (used for max slippage check in callbacks)

core/facets/GNSTradingStorage.sol (update)

  • New updateTradeMaxClosingSlippageP function

  • updateTradePosition now accepts _isPartialIncrease argument

  • Added getTradeLiquidationParams, getTradesLiquidationParams, getAllTradesLiquidationParams, and getCurrentContractsVersion

interfaces/IGeneralErrors.sol (update)

  • Added WrongOrderType() error

interfaces/libraries/IPairsStorageUtils.sol (update)

  • Added new function definitions

  • Added GroupLiquidationParamsUpdated event

  • Added MaxLiqSpreadPTooHigh, WrongLiqParamsThresholds, WrongLiqParamsLeverages, StartLiqThresholdTooHigh, EndLiqThresholdTooLow, StartLeverageTooLow, EndLeverageTooHigh

interfaces/libraries/IPriceAggregatorUtils.sol (update)

  • Adjusted getPrice function definition

  • Updated PriceRequested event: now emits tradeId instead of trader

interfaces/libraries/IPriceImpactUtils.sol (update)

  • Added new function definitions

  • Removed deprecated function definitions

  • Adjusted addPriceImpactOpenInterest and getTradePriceImpact functions definitions

  • Added ProtectionCloseFactorUpdated, ProtectionCloseFactorBlocksUpdated, and CumulativeFactorUpdated events

  • Removed isPartial from PriceImpactOpenInterestAdded event

  • Removed PriceImpactOpenInterestRemoved event

interfaces/libraries/ITradingCallbacksUtils.sol (update)

  • Added validateTriggerOpenOrderCallback and validateTriggerCloseOrderCallback functions definitions

interfaces/libraries/ITradingCommonUtils.sol (update)

  • Added TradePriceImpactInput struct to avoid stack too deep in getTradeClosingPriceImpact

interfaces/libraries/ITradingInteractionsUtils.sol (update)

  • Added updateMaxClosingSlippageP function definition

  • Adjusted closeTradeMarket and decreasePositionSize functions definitions

  • Removed WrongOrderType() error

interfaces/libraries/ITradingStorageUtils.sol (update)

  • Added new function definitions

  • Adjusted updateTradePosition function definition

  • TradeStored event now also emits the trade liquidation params

  • TradePositionUpdated now emits isPartialIncrease

  • New TradeMaxClosingSlippagePUpdated event

interfaces/libraries/IUpdatePositionSizeUtils.sol (update)

  • Added long and collateralPriceUsd properties to PositionSizeIncreaseExecuted and PositionSizeDecreaseExecuted events

interfaces/types/IBorrowingFees.sol (update)

  • LiqPriceInput struct has new liquidationParams property

interfaces/types/IPairsStorage.sol (update)

  • Added groupLiquidationParams mapping and corresponding GroupLiquidationParams struct

  • __gap length decreased from 41 to 40

interfaces/types/IPriceImpact.sol (update)

  • Added pairFactors mapping

  • __gap length decreased from 46 to 45

  • Added _open property to OiWindowUpdate struct

  • New PairFactors struct

interfaces/types/ITradingStorage.sol (update)

  • Added tradeLiquidationParams mapping

  • __gap length decreased from 39 to 38

  • New ContractsVersion enum

  • TradeInfo struct now has contractsVersion and lastPosIncreaseBlock properties, and __placeholder was reduced from uint48 to uint8

interfaces/types/IUpdatePositionSize.sol (update)

  • Added expectedPrice property to DecreasePositionSizeInput struct

  • Added priceAfterImpact property to DecreasePositionSizeValues struct

libraries/ArrayGetters.sol (update)

  • Added getTradesLiquidationParams and getAllTradesLiquidationParams getters

libraries/BorrowingFeesUtils.sol (update)

  • getTradeLiquidationPrice: calculate closingFeesCollateral using new TradingCommonUtils.getTotalClosingFeesCollateral helper, pass input liquidation params, trade contracts version, and pair spread % to _getTradeLiquidationPrice

  • _getTradeLiquidationPrice: new _liquidationParams, _contractsVersion, and _pairSpreadP arguments, _collateralPrecisionDelta is now uint256 (saves one var to avoid stack too deep), calculate liqPnlThresholdP using new TradingCommonUtils.getLiqPnlThresholdP helper, in collateralLiqNegativePnlInt calculation divide by 1e10 because of new liq threshold precision, if trade opened after v9.2 make liquidation price distance lower by closing spread (= 1/2 pair spread %, capped at maxLiqSpreadP)

libraries/ConstantsUtils.sol (update)

  • Replaced MAX_SL_P by SL_LIQ_BUFFER_P=10%, renamed LIQ_THRESHOLD_P to LEGACY_LIQ_THRESHOLD_P, added MIN_LIQ_THRESHOLD_P=50%/MAX_LIQ_SPREAD_P=0.05%/DEFAULT_MAX_CLOSING_SLIPPAGE_P=1%

libraries/PairsStorageUtils.sol (update)

  • New initializeGroupLiquidationParams function: initializes group liquidation params for all existing groups

  • New setGroupLiquidationParams function: used to update a group's liquidation params (only affects trades opened after the change)

  • New getGroupLiquidationParams and getPairLiquidationParams getters

libraries/PriceAggregatorUtils.sol (update)

  • getPrice: now accepts _tradeId argument instead of _trader, passes trader/index/orderType data to linkRequest

libraries/PriceImpactUtils.sol (update)

  • MAX_WINDOWS_DURATION lowered from 30 days to 10 minutes, MIN_WINDOWS_DURATION lowered from 10 minutes to 1 minute

  • New initializePairFactors function that initializes pairs factors

  • New setProtectionCloseFactors to set the protection close factors for a set of pairs

  • New setProtectionCloseFactorBlocks to set the protection close factor duration in blocks for a set of pairs

  • New setCumulativeFactors to set the cumulative factors for a set of pairs

  • addPriceImpactOpenInterest: Removed partials logic that moved previous trade OI to current window if not expired, changed logic to decide if adds to long or short part of window (opening a long / closing a short adds to long window, opening a short / closing a long adds to short window), removed lastWindowOiUsd update (deprecated)

  • Removed removePriceImpactOpenInterest and getTradeLastWindowOiUsd

  • getTradePriceImpact: new _isPnlPositive/_open/_lastPosIncreaseBlock/_contractsVersion arguments, now loads pairFactors for pair, uses opposite side depth when _open = false, uses opposite side price impact OI when _open = false, passes _open, protectionCloseFactor (only when _isPnlPositive is true, _open is false, protectionCloseFactor isn't zero, and protection close factor didn't expire, otherwise passes 1e10), cumulativeFactor (when not zero, otherwise passes 1e10), and _contractsVersion to _getTradePriceImpact

  • Removed getTradePriceImpactInfo (deprecated)

  • New getPairFactors getter

  • _getTradePriceImpact: new _open, _protectionCloseFactor, _cumulativeFactor, _contractsVersion arguments, returns early 0 price impact if trade opened before v9.2 and _open = false (no closing price impact for trades opened before v9.2 since they paid it fully on open), multiplies _startOpenInterestUsd by _cumulativeFactor, multiplies by _protectionCloseFactor instead of 1e10 in priceImpactP calculation and divides result by 2 if trade opened after v9.2 (charge half price impact if trade opened after v9.2 since they paid half on open already, for trades opened before v9.2 charges full opening price impact), sets _long to !_long if _open is false to invert the price impact direction on close

libraries/TradingCallbacksUtils.sol (update)

  • closeTradeMarketCallback: use new _getTradeInfo getter, Add TradingCommonUtils.getTradeClosingPriceImpact call, added max slippage cancel reason check (uses default max slippage % if tradeInfo.maxSlippageP not set), use priceAfterImpact (= market price + closing spread and price impact) instead of _a.price to calculate v.profitP, emit priceAfterImpact and priceImpactP in event

  • executeTriggerOpenOrderCallback: moved all cancel reason and spread/price impact logic to validateTriggerOpenOrderCallback

  • executeTriggerCloseOrderCallback: moved all cancel reason and spread/price impact logic to validateTriggerCloseOrderCallback, emit priceImpactP in LimitExecuted event

  • validateTriggerOpenOrderCallback: new getter that contains the extracted cancel reason logic of executeTriggerOpenOrderCallback

  • validateTriggerCloseOrderCallback: new getter that contains the extracted cancel reason logic of executeTriggerCloseOrderCallback, for SLs and TPs (not liquidations) set v.executionPrice to TradingCommonUtils.getTradeClosingPriceImpact result to take into account closing spread and impact, added max slippage cancel reason check for everything but liquidations (uses default max slippage % if tradeInfo.maxSlippageP not set)

  • _openTradePrep: no logic change, just use new TradingCommonUtils.getTradeOpeningPriceImpact helper to calculate opening price impact

  • New _getTradeInfo getter

libraries/TradingCommonUtils.sol (update)

  • getMarketExecutionPrice: new _open/_contractsVersion arguments, returns early with 0 spread if _open = false and _contractsVersion = before v9.2, divides spread by 2 if _contractsVersion >= v9.2, inverts spread direction when _open = false

  • getTradeValuePure: combined _borrowingFeeCollateral and _closingFeeCollateral into _feesCollateral to avoid stack too deep, added _liqPnlThresholdP argument, collateralLiqThreshold is now uint256 and uses _liqPnlThresholdP instead of ConstantsUtils.LIQ_THRESHOLD_P and is adjusted for 1e10 precision, added int256 conversion for collateralLiqThreshold in return statement

  • getLiqPnlThresholdP: new pure function that returns the corresponding liquidation PnL threshold percentage to use depending on a trade's liquidation params and leverage; uses new logic (linearly decreasing liq pnl threshold as leverage increases, capped between two values)

  • getTradeLiquidationPrice: pass the stored trade's liquidation params

  • getTradeValueCollateral: pass borrowingFeesCollateral + _closingFeesCollateral to getTradeValuePure instead of passing them separately, and also pass getTradeLiqPnlThresholdP(_trade)

  • getTradeOpeningPriceImpact: New view helper to calculate the price impact % and price after spread + price impact for trade openings / partial adds

  • getTradeClosingPriceImpact: New view helper that returns the closing price impact %, price after closing spread and impact, and net trade value used to determine whether net pnl is positive or not; returns early 0% price impact for trades opened before v9.2, otherwise calculates net trade value (taking into account pnl, spread, price impact, closing fees, and borrowing fees) without protection factor and compares it to the initial trade collateral to determine the _isPnlPositive value passed to getTradePriceImpact which determines the final returned priceImpactP and priceAfterImpact values

  • getTradeLiqPnlThresholdP: new getter that returns the value of getLiqPnlThresholdP by passing the trade's stored liquidation params and its leverage

  • getTotalClosingFeesCollateral: new getter that returns a trade's closing fee based on its _collateralIndex/_pairIndex/_positionSizeCollateral, used in BorrowingFeesUtils.getTradeLiquidationPrice/TradingCommonUtils.getTradeClosingPriceImpact/DecreasePositionSizeUtils.validateRequest

  • Renamed addOiCollateral to updateOi, now accepts _open argument and passes it to handleTradeBorrowingCallback and addPriceImpactOpenInterest

  • Renamed addTradeOiCollateral to updateOiTrade, now accepts _open argument and passes it to updateOi

  • Removed removeOiCollateral and removeTradeOiCollateral

  • handleOiDelta now uses updateOi, passes _open = true when _newPositionSizeCollateral > existingPositionSizeCollateral and _open = false when _newPositionSizeCollateral < existingPositionSizeCollateral

libraries/TradingInteractionsUtils.sol (update)

  • New updateMaxClosingSlippageP function that simply calls GNSTradingStorage.updateTradeMaxClosingSlippageP

  • closeTradeMarket: now accepts _expectedPrice, reverts if _expectedPrice is 0, sets pendingOrder.trade.openPrice to _expectedPrice, passes trade id to getPrice

  • decreasePositionSize: now accepts _expectedPrice, passes it to requestDecreasePositionSize

  • triggerOrder: no longer turn LIQ orders into SL orders when SL is closer, uses TradingCommonUtils.getTradeOpeningPriceImpact to calculate priceImpactP

  • _openTrade: uses TradingCommonUtils.getTradeOpeningPriceImpact to calculate priceImpactP, passes trade id to getPrice

  • _getPriceTriggerOrder: passes trade id to getPrice

libraries/TradingStorageUtils.sol (update)

  • storeTrade: Fetches the corresponding pair's liquidation params and stores them into the new tradeLiquidationParams mapping, limits the trade SL distance using the new _limitTradeSlDistance helper, sets _tradeInfo.contractsVersion to the current version using getCurrentContractsVersion(), sets _tradeInfo.lastPosIncreaseBlock to current block, no longer sets _tradeInfo.lastOiUpdateTs = 0 because corresponding logic was deprecated, calls updateOiTrade with _open = true instead of addTradeOiCollateral, emits the trade's liquidation params

  • New updateTradeMaxClosingSlippageP setter

  • updateTradePosition/updateOpenOrderDetails/updateTradeSl: limit the trade's SL distance using the new _limitTradeSlDistance helper instead of _limitSlDistance

  • updateTradePosition: new _isPartialIncrease argument, sets the trade's stored liquidation params to the current pair liquidation params when _isPartialIncrease = true and sets i.lastPosIncreaseBlock to current block, emits _isPartialIncrease in TradePositionUpdated event

  • closeTrade: calls updateOiTrade with _open = false instead of removeTradeOiCollateral

  • getTradeLiquidationParams: new getter to return the new tradeLiquidationParams mapping values

  • getCurrentContractsVersion: new getter to return the current contracts version (will need to be updated at each significant update)

  • _limitSlDistance: accepts new _liqPnlThresholdP argument, calculates minSlP as _liqPnlThresholdP - ConstantsUtils.SL_LIQ_BUFFER_P, uses calculated minSlP instead of ConstantsUtils.MAX_SL_P, adjustments done for 1e10 precision of minSlP

  • _limitTradeSlDistance: new view wrapper accepting _trade and _newSl arguments; returns a trade's capped SL distance based on its open price, leverage, new stop loss value, whether it's a long or a short, and based on its liquidation pnl % threshold fetched using TradingCommonUtils.getTradeLiqPnlThresholdP(_trade)

libraries/updateLeverage/UpdateLeverageLifecycles.sol (update)

  • _initiateRequest: small adjustment to avoid stack too deep, now passes trade id to getPrice

  • _prepareCallbackValues: pass stored trade liquidation params in values.liqPrice calculation

  • _handleCallback: pass _isPartialIncrease = false to updateTradePosition

libraries/updatePositionSize/DecreasePositionSizeUtils.sol (update)

  • validateRequest: calculate closingFeesCollateral using new TradingCommonUtils.getTotalClosingFeesCollateral helper, revert if input.expectedPrice is 0

  • prepareCallbackValues: added values.priceAfterImpact calculation using new TradingCommonUtils.getTradeClosingPriceImpact helper, values.existingPnlCollateral now uses uint64(values.priceAfterImpact) instead of _answer.price

  • validateCallback: now accepts _pendingOrder (to fetch expected price), added max slippage calculations and corresponding cancel reason check (uses default max slippage % if tradeInfo.maxSlippageP not set)

  • updateTradeSuccess: pass _isPartialIncrease = false to updateTradePosition

libraries/updatePositionSize/IncreasePositionSizeUtils.sol (update)

  • prepareCallbackValues: Uses TradingCommonUtils.getTradeOpeningPriceImpact to calculate values.priceAfterImpact, passes current pair liquidation params to getTradeLiquidationPrice for values.newLiqPrice calculation (already checks using new liquidation params since trade liquidation params will be refreshed on success callback)

  • updateTradeSuccess: pass _isPartialIncrease = true to updateTradePosition

libraries/updatePositionSize/UpdatePositionSizeLifecycles.sol (update)

  • requestDecreasePositionSize: passes _input.expectedPrice to _initiateRequest

  • _initiateRequest: passes trade id to getPrice

  • executeIncreasePositionSizeMarket/executeDecreasePositionSizeMarket: pass trade long and current collateral/usd price to event

  • executeDecreasePositionSizeMarket: pass _order to DecreasePositionSizeUtils.validateCallback