v9 Update

Summary

  • New features: update trade leverage, update trade position size

  • Important changes: min position size requirement replaced by minimum fee (trade collateral must be >= 5x min fee when opening), liquidation price now takes into account closing fees, getPnlPercent negative PnL capped at -100%

  • Important refactors: TradingStorageUtils now handles all OI update calls, constants all moved to ConstantsUtils, common helpers moved to TradingCommonUtils, removed GNSTradingStateCopy facet, tradeInfo.collateralPriceUsd/tradeInfo.lastOiUpdateTs values now set in GNSPriceImpact.addPriceImpactOpenInterest instead of GNSTradingStorage.storeTrade

  • Bugfixes: liquidation fees now don't take into account fee tiers, getTradeValuePure returns 0 for liquidations (due to precision loss it was possible liquidation price was reached but pnl + borrowing fees didn't reach -90% PnL), and _openTrade now hardcodes _trade.__placeholder input to 0

Full Changelog

core/facets/GNSBorrowingFees (update)

  • New resetTradeBorrowingFees function (pending borrowing fees are charged and reset on partial updates)

core/facets/GNSPairsStorage (update)

  • New pairMinFeeUsd getter function (trade fee at minimum position size, replaces minimum position size requirement)

core/facets/GNSPriceImpact (update)

  • addPriceImpactOpenInterest and removePriceImpactOpenInterest now accept trader/index/oi delta in collateral tokens oi delta in USD/pairIndex/long, and removePriceImpactOpenInterest no longer accepts _addTs

  • Added getTradeLastWindowOiUsd and getTradePriceImpactInfo getters

core/facets/GNSTradingCallbacks (update)

  • New callback functions for partials: updateLeverageCallback, increasePositionSizeMarketCallback, decreasePositionSizeMarketCallback

core/facets/GNSTradingInteractions (update)

  • New functions to initiate partial updates: updateLeverage, increasePositionSize, decreasePositionSize

  • openTradeMarketTimeout and closeTradeMarketTimeout turned into cancelOrderAfterTimeout (supports all market order types including partials)

core/facets/GNSTradingStateCopy.sol (removed)

  • Not needed anymore now that v8 transition is done

core/facets/GNSTradingStorage (update)

  • New updateTradePosition function to update a trade's collateral, leverage, and open price

  • Array getters (eg. getTraders) now call the new ArrayGetters library

  • getPnlPercent function removed (moved to TradingCommonUtils)

  • getPendingOpenOrderType moved to ConstantsUtils

interfaces/libraries/IBorrowingFeesUtils.sol (update)

  • BorrowingInitialAccFeesStored event now emits whether trade is long or short

interfaces/libraries/IPriceImpactUtils.sol (update)

  • PriceImpactOpenInterestAdded event now emits isPartial

interfaces/libraries/ITradingCallbacksUtils.sol (update)

  • Now inherits IUpdateLeverageUtils (leverage updates types and events), IUpdatePositionSizeUtils (position size updates types and events), and ITradingCommonUtils (fee charged events), so that IGNSMultiCollatDiamond also inherits those

  • Fee charged events moved to ITradingCommonUtils because all functions that charge fees were moved there (since now they're used in many different places other than TradingCallbacksUtils, eg. partials libraries)

interfaces/libraries/ITradingCommonUtils.sol (new)

  • Contains fee charged events

interfaces/libraries/ITradingInteractionsUtils.sol (update)

  • Now inherits IUpdateLeverageUtils (leverage updates types and events), IUpdatePositionSizeUtils (position size updates types and events)

  • AbovePairMaxOi and AboveGroupMaxOi errors consolidated into AboveExposureLimits, BelowMinPositionSizeUsd error removed, added ConflictingPendingOrder (eg. when trying to close trade that has a pending partial update) and InsufficientCollateral (trade collateral < 5 * min fee when opening trade) errors

interfaces/libraries/ITradingStateCopyUtils.sol (removed)

  • Not needed anymore now that v8 transition is done

interfaces/libraries/ITradingStorageUtils.sol (update)

  • Removed getPendingOpenOrderType (moved to ConstantsUtils)

  • Added TradePositionUpdated event

interfaces/libraries/IUpdateLeverageUtils.sol (new)

  • Contains update leverage events (LeverageUpdateInitiated, LeverageUpdateExecuted) and inherits IUpdateLeverage for types

interfaces/libraries/IUpdatePositionSizeUtils.sol (new)

  • Contains update position size events (PositionSizeUpdateInitiated, PositionSizeIncreaseExecuted, PositionSizeDecreaseExecuted) and inherits IUpdatePositionSize for types

interfaces/types/IBorrowingFees.sol (update)

  • Added useBorrowingFees property to LiqPriceInput struct (in increase position size callback we calculate new liq price using new leverage and collateral (- borrowing fees) but borrowing fees haven't been reset yet so we pass useBorrowingFees=false, all other calls pass true)

interfaces/types/IPriceImpact.sol (update)

  • New tradePriceImpactInfos mapping

  • OiWindowUpdate struct (used for events) now also has trader and index properties

  • New TradePriceImpactInfo struct to store lastWindowOiUsd (and potentially more, has a placeholder)

interfaces/types/ITradingCallbacks.sol (update)

  • Added LIQ_REACHED to CancelReason enum (we cancel all partial updates if existing/updated trade can be liquidated)

  • Added closingFeeCollateral, triggerFeeCollateral, and collateralLeftInStorage to Values struct

interfaces/types/ITradingStateCopy.sol (removed)

  • Not needed anymore now that v8 transition is done

interfaces/types/ITradingStorage.sol (update)

  • Added UPDATE_LEVERAGE, MARKET_PARTIAL_OPEN, and MARKET_PARTIAL_CLOSE values to PendingOrderType enum

interfaces/types/IUpdateLeverage.sol (new)

  • Contains useful structs for leverage updates (UpdateLeverageInput for request, UpdateLeverageValues for callback)

interfaces/types/IUpdatePositionSize.sol (new)

  • Contains useful structs for position size updates (DecreasePositionSizeInput and IncreasePositionSizeInput for request, DecreasePositionSizeValues and IncreasePositionSizeValues for callback)

libraries/ArrayGetters.sol (new)

  • New external library to reduce TradingStorageUtils size

  • Array getters are what take the most amount of bytecode in a contract generally, so if needed we can move them in this new library

  • For now only contains array getters of TradingStorageUtils but it could contain getters of other facets if needed too

libraries/BorrowingFeesUtils.sol (update)

  • LIQ_THRESHOLD_P AND P_1 removed, replaced by ConstantsUtils.LIQ_THRESHOLD_P and ConstantsUtils.P_10 respectively (same values)

  • handleTradeBorrowingCallback: initial acc fees initalization when _open = true replaced by resetTradeBorrowingFees call

  • New resetTradeBorrowingFees function to reset a trade's borrowing fees to 0 by setting its initial acc fees to current acc pair/group borrowing fees, useful after partial updates since we charge pending borrowing fees and after we need to reset them to 0 to not charge them again later

  • getTradeLiquidationPrice now calculates and passes closing fees to _getTradeLiquidationPrice, and logic adjusted for _input.useBorrowingFees (if false, passes 0 borrowing fees to _getTradeLiquidationPrice)

  • _getTradeLiquidationPrice's _borrowingFeeCollateral input renamed to _feesCollateral, now expects closing fees + borrowing fees instead of just borrowing fees, but calculations stay the same

libraries/ConstantsUtils.sol (new)

  • New internal library for useful constants (P_10, MAX_SL_P, MAX_PNL_P, LIQ_THRESHOLD_P, MAX_OPEN_NEGATIVE_PNL_P)

  • Values for these constants didn't change, they were just moved to this library

libraries/PairsStorageUtils.sol (update)

  • Added pairMinFeeUsd getter, uses gov fee * 2 + trigger fee on min position size usd (eg. 0.08% on crypto)

libraries/PriceAggregatorUtils.sol (update)

  • PRECISION constant replaced by ConstantsUtils.P_10

  • getPrice: isLookback is now equal to !ConstantsUtils.isOrderTypeMarket

  • fulfill: added new callbacks for UPDATE_LEVERAGE, MARKET_PARTIAL_OPEN, and MARKET_PARTIAL_CLOSE order types (explicit check)

  • getLinkFee: when _positionSizeCollateral > 0 (doesn't bypass trigger link fee) uses TradingCommonUtils.getPositionSizeCollateralBasis to charge pairOracleFeeP on max(pos size, min pos size)

libraries/PriceImpactUtils.sol (update)

  • Replaced PRECISION by ConstantsUtils.P_10

  • addPriceImpactOpenInterest: arguments changed from _openInterestUsd/_pairIndex/_long to _trader/_index/_oiDeltaCollateral, now responsible for converting the collateral OI passed to USD value using current collateral/usd price, added logic for partials: if last window where OI was added for trade hasn't expired then remove OI from that window and add move it to the current window scaling to the new collateral/usd price, now responsible (instead of GNSTradingStorage) for setting tradeInfo.lastOiUpdateTs and tradeInfo.collateralPriceUsd, and finally stores the new tradePriceImpactInfo.lastWindowOiUsd value

  • removePriceImpactOpenInterest: arguments changed from _openInterestUsd/_pairIndex/_long/_addTs to _trader/_index/_oiDeltaCollateral, now fetches timestamp when OI was last added from within the function using tradeInfo.lastOiUpdateTs, responsible for converting the OI collateral value input to USD using tradeInfo.collateralPriceUsd, now caps the removal of OI to the new lastWindowOiUsd value (since any trade OI that's not part of lastWindowOiUsd has necessarily expired and is in another older window), and reduces lastWindowOiUsd by the oi delta so it stays accurate

  • New getTradeLastWindowOiUsd getter that simply returns lastWindowOiUsd when it's set to a value > 0, otherwise returns the USD position size of the trade at the time of opening (useful for trades opened before v9)

  • New getTradePriceImpactInfo getter to return values of the new mapping

libraries/ReferralsUtils.sol (update)

  • Replaced PRECISION by ConstantsUtils.P_10

libraries/TradingCallbacksUtils.sol (update)

  • PRECISION replaced by ConstantsUtils.P_10, LIQ_THRESHOLD_P by ConstantsUtils.LIQ_THRESHOLD_P, and MAX_OPEN_NEGATIVE_PNL_P by ConstantsUtils.MAX_OPEN_NEGATIVE_PNL_P

  • _transferCollateralToAddress replaced by TradingCommonUtils.transferCollateralTo, _updateTraderPoints replaced by TradingCommonUtils.updateFeeTierPoints, _handleGovFees replaced by radingCommonUtils.distributeGovFeeCollateral, _getPositionSizeCollateral replaced by TradingCommonUtils.getPositionSizeCollateral, diamond.getPnlPercent replaced by TradingCommonUtils.getPnlPercent, _getTradeValue replaced by TradingCommonUtils.getTradeValueCollateral, _marketExecutionPrice replaced by TradingCommonUtils.getMarketExecutionPrice, _withinExposureLimits replaced by TradingCommonUtils.isWithinExposureLimits

  • When a trade is canceled (openTradeMarketCallback, closeTradeMarketCallback) we charge gov fee on min pos size / 2 instead of gov fee on full position size

  • closeTradeMarketCallback: v.positionSizeCollateral removed (was used to calculate closing fees), closing fees calculation moved to inside _unregisterTrade, removed OI removal when canceled (now handled inside GNSTradingStorage.updateTradeCollateralAmount)

  • executeTriggerCloseOrderCallback: v.positionSizeCollateral removed (was used to calculate closing fees), v.liqPrice uses TradingCommonUtils wrapper, v.reward1 calculation removed (now done inside _unregisterTrade) and same conditions used to determine cancelReason directly instead, removed v.gnsPriceCollateral (unused), just pass order type to _unregisterTrade instead of closing fees, no longer call _handleTriggerRewards (done from within _unregisterTrade depending on orderType)

  • Added: updateLeverageCallback (tradingActivated modifier), increasePositionSizeMarketCallback (tradingActivated modifier), decreasePositionSizeMarketCallback (tradingActivatedOrCloseOnly modifier) for partials, they just return early if order is not open like for other callbacks and call the corresponding UpdateLeverageLifecycles/UpdatePositionSizeLifecycles execute callback function

  • Removed: _transferCollateralToAddress, _distributeStakingReward, _sendToVault, _handleTriggerRewards, _handleGovFees, _updateTraderPoints, _distributeReferralReward, _handleInternalOnRegisterUpdates, _convertCollateralToUsd, _convertCollateralToGns, _getTradeValuePure, _marketExecutionPrice, _getTradeValue, _withinExposureLimits, _getGToken, _getPositionSizeCollateral (all moved/refactored to TradingCommonUtils)

  • _registerTrade: simplified a lot, all opening fees calculations / distributions moved to TradingCommonUtils.processOpeningFees, _handleInternalOnRegisterUpdates call removed as GNSTradingStorage manages OI deltas now (directly in storeTrade)

  • _unregisterTrade: _marketOrder input replaced by _orderType, no longer accepts closing fees as input, moved fee tier closing fees calculations/gToken fee distribution/GNS staking fee distribution/collateralLeftInStorage calculation to TradingCommonUtils.processClosingFees, removed handleTradeBorrowingCallback/removePriceImpactOpenInterest calls as GNSTradingStorage.closeTrade now handles OI deltas, now calls TradingCommonUtils.handleTradePnl for PnL/collateral transfers logic

  • _openTradePrep: pass positionSizeCollateral to isWithinExposureLimits instead of collateral and leverage

libraries/TradingCommonUtils.sol (new)

  • New external library that contains helpers called by multiple libraries

  • Contains useful getters (pnl, position size, etc.), collateral/pnl transfer functions, fee distributions, OI delta handling

  • Mostly renames of previous private functions in TradingCallbacksUtils and TradingInteractionsUtils

  • getPnlPercent: now caps negative PnL at -100%

  • getMinPositionSizeCollateral: new function that converts min pos usd to min pos collateral and returns it

  • getPositionSizeCollateralBasis: returns max(position size input, min position size collateral) for fees calculations

  • getTradeValuePure: accepts _orderType and returns 0 if liquidation, now takes into account closing fees for liquidation threshold

  • isWithinExposureLimits: now accepts _positionSizeCollateralDelta instead of trade collateral and leverage (so it works for partials too)

  • getTradeBorrowingFeeCollateral: useful wrapper that takes trade struct as input

  • getTradeLiquidationPrice: same just a wrapper that takes trade struct as input

  • getGovFeeCollateral: new getter that returns gov fee after fee tier based on position size

  • getClosingFeesCollateral: new getter that returns vault and gns staking fees based on closing fee/trigger fee/order type

  • revertIfTradeHasPendingMarketOrder: new helper to prevent two pending market orders on the same trade

  • transferCollateralFrom: new helper to transfer collateral from trader to diamond if amount > 0

  • handleTradePnl: new helper to handle collateral/pnl transfers between vault/diamond and trader (used for full closes and partial closes)

  • distributeVaultFeeCollateral: new helper to distribute vault reward

  • distributeExactGovFeeCollateral: new helper to distribute an exact amount of gov fee

  • processOpeningFees: new helper that contains the previous fee calculation / distribution logic of _registerTrade used for both full and partial trade open and returns the total opening fee charged (difference is it charges fees on max(position size input, min position size) and it uses !ConstantsUtils.isOrderTypeMarket to know if it should distribute the trigger fee)

  • processClosingFees: new helper that contains the previous fee calculation / distribution logic of _unregisterTrade used for full trade closes only and returns the value struct with the fee values and collateralLeftInStorage (difference is it charges fees on max(position size input, min position size), it calculates the closing and trigger fees based on the order type (and only applies fee tier if order type is not liquidation), it calculates the vault and gns staking fees by calling getClosingFeesCollateral, it only distributes the gns staking and vault fees if trade collateral is big enough to pay (otherwise it's still charged but as negative PnL only), and it distributes the trigger gns fee depending on the order type using !ConstantsUtils.isOrderTypeMarket)

  • addOiCollateral: new helper to add borrowing/price impact windows OI in one call (flexible amount)

  • addTradeOiCollateral: new helper to add borrowing/price impact windows OI in one call (trade position size)

  • removeOiCollateral: new helper to remove borrowing/price impact windows OI in one call (flexible amount)

  • removeTradeOiCollateral: new helper to remove borrowing/price impact windows OI in one call (trade position size)

  • handleOiDelta: new helper that either calls addOiCollateral or removeOiCollateral based on a trade's new position size and its existing position size

libraries/TradingInteractionsUtils.sol (update)

  • PRECISION replaced by ConstantsUtils.P_10, MAX_SL_P replaced by ConstantsUtils.MAX_SL_P, and MAX_OPEN_NEGATIVE_PNL_P replaced by ConstantsUtils.MAX_OPEN_NEGATIVE_PNL_P

  • getPendingOrderType calls now use ConstantsUtils

  • Replaced _getPositionSizeCollateral by TradingCommonUtils.getPositionSizeCollateral, _transferCollateralToTrader by TradingCommonUtils.transferCollateralTo, and _receiveCollateralFromTrader by TradingCommonUtils.transferCollateralFrom (those 3 private functions were removed)

  • closeTradeMarket: Replace AlreadyBeingMarketClosed() check by TradingCommonUtils.revertIfTradeHasPendingMarketOrder call

  • Added: updateLeverage, increasePositionSize, decreasePositionSize that call the create request function in their lifecycles library

  • triggerOrder: use TradingCommonUtils.getTradeLiquidationPrice wrapper

  • openTradeMarketTimeout/closeTradeMarketTimeout: removed in favor of cancelOrderAfterTimeout which only accepts an order index now instead of the full order id (impossible to input another address than yours, removes need for this check)

  • triggerOrder: use ConstantsUtils.isOrderTypeMarket for WrongOrderType check

  • cancelOrderAfterTimeout: Supports all market orders (ConstantsUtils.isOrderTypeMarket), transfers back trade collateral for MARKET_OPEN, transfers back partial collateral for UPDATE_LEVERAGE (leverage decrease), and transfers back partial collateral for MARKET_PARTIAL_OPEN (no longer calls closeTradeMarket() again for MARKET_CLOSE orders)

  • _openTrade: overwrite _trade.__placeholder to 0, consolidated AbovePairMaxOi and AboveGroupMaxOi checks into AboveExposureLimits using TradingCommonUtils.isWithinExposureLimits, replaced BelowMinPositionSizeUsd check by InsufficientCollateral (trade collateral must be >= min fee)

libraries/TradingStateCopyUtils.sol (removed)

  • Not needed anymore now that v8 transition is done

libraries/TradingStorageUtils.sol (update)

  • Turned into external library (otherwise GNSTradingStorage facet contract would be above max limit)

  • PRICE_PRECISION replaced by ConstantsUtils.P_10, MAX_SL_P replaced by ConstantsUtils.MAX_SL_P, MAX_PNL_P not used anymore

  • storeTrade: removed TradeInfoCollateralPriceUsdZero check (now tradeInfo.collateralPriceUsd is set by GNSPriceImpact.addPriceImpactOpenInterest), enforces _tradeInfo.lastOiUpdateTs to 0 to make sure isPartial = false when calling addPriceImpactOpenInterest, added TradingCommonUtils.addTradeOiCollateral call when tradeType is TRADE

  • updateTradeCollateralAmount: added TradingCommonUtils.handleOiDelta call, added i.createdBlock update (because reducing a trade's collateral now potentially changes the trade's liquidation price with the liq price taking into account closing fees and closing fees having a minimum value)

  • updateTradePosition: new helper to update a trade's collateralAmount/leverage/openPrice, same checks as updateTradeCollateralAmount (trade must be open, trade type must be TRADE, and additionally new collateral * new leverage > 0 and new openPrice > 0) calls _limitTpDistance and _limitSlDistance again based on updated values, updates i.createdBlock/tpLastUpdatedBlock/slLastUpdatedBlock so lookbacks work properly (tp/sl potentially updated, liquidation price updated)

  • closeTrade: added TradingCommonUtils.removeTradeOiCollateral call when tradeType is TRADE

  • Array getters (getTraders, getTrades, getAllTrades, getTradeInfos, getAllTradeInfos, getPendingOrders, getAllPendingOrders) moved to new ArrayGetters external library

  • getPnlPercent moved to TradingCommonUtils

  • _validateTrade: use TradingCommonUtils.getPositionSizeCollateral

  • Removed getPendingOpenOrderType (moved to ConstantsUtils)

libraries/updateLeverage/UpdateLeverageLifecycles.sol (new)

  • New external library to handle leverage updates lifecycles

  • requestUpdateLeverage: create request (used by TradingInteractionsUtils)

  • executeUpdateLeverage: callback (used by TradingCallbacksUtils)

libraries/updatePositionSize/DecreasePositionSizeUtils.sol (new)

  • New internal library to handle position size decreases, used by the new UpdatePositionSizeLifecycles library

  • validateRequest: request validation, prepareCallbackValues: all the calculations, validateCallback: callback validation, updateTradeSuccess: success callback, handleCanceled: canceled callback

libraries/updatePositionSize/IncreasePositionSizeUtils.sol (new)

  • New internal library to handle position size increases, used by the new UpdatePositionSizeLifecycles library

  • validateRequest: request validation, prepareCallbackValues: all the calculations, validateCallback: callback validation, updateTradeSuccess: success callback, handleCanceled: canceled callback

libraries/updatePositionSize/UpdatePositionSizeLifecycles.sol (new)

  • New external library to handle position size updates lifecycles

  • requestIncreasePositionSize: create position size increase request (used by TradingInteractionsUtils)

  • requestDecreasePositionSize: create position size decrease request (used by TradingInteractionsUtils)

  • executeIncreasePositionSizeMarket: increase position size callback (used by TradingCallbacksUtils)

  • executeDecreasePositionSizeMarket: decrease position size callback (used by TradingCallbacksUtils)

Last updated