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