v10 migration
Notice: These documents are currently in progress. For any questions or clarifications, please contact the team.
Current version: @gainsnetwork/sdk@1.0.0-rc1
v10 Changes - Overview
New funding fees (skew-based, only on v10 positions)
New borrowing fees v2 (alongside existing v1)
New P&L withdrawal feature (withdraw profits without closing)
New counter trade type (fee discounts for improving skew)
New skew price impact
New market max skew limits
Fees no longer impact position size (exact position sizes)
Modified borrowing fees v1 (uses dynamic OI)
Modified partial update requirements (use effective leverage)
Modified liquidation, pnl, fees calculations
Pre and post v10 OI stored separately
Pre-v10 trades cannot partial add
New accounting: TradeFeesData and UiRealizedPnlData
New Trade fields: positionSizeToken and isCounterTrade
Developer Notes - Overview
SDK has been updated to support v10 more effectively than previous versions
Backend transforms and converters are available (fetching is still separate)
Transform trading variables:
transformGlobalTradingVariables
Transform global trades:
transformGlobalTrades
All functions expect backend types
Additional feature support
Holding fees
Action fees
Price impact
PnL
Liquidations
Counter trade validation
Effective leverage
Market holding rates
Market leverage requirements
Market open interest
Market price
New context builders
More declarative development pattern
SDK functions mirror contract functions. But they don't fetch data, instead rely on all data provided
Provide large trading variables object and context builder will prepare struct for specific functions with all expected data
Integration Guide
1. New Funding Fees
Funding fees are skew-based fees that balance long/short exposure.
Trade-Specific Funding Fees:
import { buildFundingContext } from "@gainsnetwork/sdk/trade/fees/fundingFees/builder";
import {
getTradeFundingFeesCollateral,
getAvgFundingRatePerSecondP,
} from "@gainsnetwork/sdk/trade/fees/fundingFees";
// Build funding context
const fundingContext = buildFundingContext(
tradingVariables,
collateralIndex,
pairIndex,
currentTimestamp
);
// Calculate funding fees for a trade
const fundingFees = getTradeFundingFeesCollateral(
trade,
currentTimestamp,
fundingContext
);
// Get current funding rate
const { avgFundingRatePerSecondP, currentFundingRatePerSecondP } =
getAvgFundingRatePerSecondP(fundingContext, currentTimestamp);
Display helpers:
import {
convertRatePerSecondToAPR,
formatHoldingFeeRate,
} from "@gainsnetwork/sdk/markets/holdingFees";
import { fundingRateToAPR } from "@gainsnetwork/sdk/trade/fees/fundingFees/converter";
// Convert to annual percentage rate
const apr = convertRatePerSecondToAPR(ratePerSecond);
const fundingAPR = fundingRateToAPR(fundingRatePerSecond);
// Format for display (e.g., "0.25%")
const formatted = formatHoldingFeeRate(rate);
2. New Borrowing Fees v2
Borrowing fees v2 work alongside funding fees with a simplified rate-based model.
Context Builder & Calculation:
import { buildBorrowingV2Context } from "@gainsnetworks/sdk/trade/fees/borrowingV2/builder";
import { getTradeBorrowingFeesCollateral } from "@gainsnetworks/sdk/trade/fees/borrowingV2";
// Build borrowing v2 context
const borrowingV2Context = buildBorrowingV2Context(
tradingVariables,
collateralIndex,
pairIndex,
currentTimestamp
);
// Calculate borrowing fees for a trade
const borrowingFees = getTradeBorrowingFeesCollateral(
trade,
currentTimestamp,
oraclePrice,
borrowingV2Context
);
Display helpers:
import { borrowingRateToAPR } from "@gainsnetworks/sdk/trade/fees/borrowingV2/converter";
// Convert borrowing rate to APR for display
const borrowingAPR = borrowingRateToAPR(borrowingRatePerSecond);
3. P&L Withdrawal Feature
Users can withdraw profits without closing their position. This maintains leverage while extracting gains.
Contract Interaction:
// Direct contract call (no SDK wrapper currently)
const tx = await gnsMultiCollatDiamond.withdrawPositivePnl(
tradeIndex,
amountCollateral // in collateral precision (e.g., 6 decimals for USDC)
);
Important behavior: If amountCollateral
exceeds available positive PnL, the contract will automatically withdraw only the maximum available amount (no revert).
To withdraw all available PnL:
const MAX_UINT120 = BigNumber.from(2).pow(120).sub(1);
const tx = await gnsMultiCollatDiamond.withdrawPositivePnl(
tradeIndex,
MAX_UINT120 // Will be capped to available PnL
);
Integration requirements:
Calculate withdrawable P&L:
tradeValue - initialCollateral
(when positive)Show withdrawable amount in UI when position is in profit
Listen for
TradePositivePnlWithdrawn
event to update UIUpdate position display after withdrawal:
collateralAmount
increasespositionSizeToken
remains unchangedTrack
pnlWithdrawnCollateral
for total withdrawn
4. Counter Trade Type
Counter trades improve market balance and receive fee discounts.
Creating a Counter Trade:
// When opening a trade, set the isCounterTrade flag
const tradeStruct = {
// ... other trade parameters ...
isCounterTrade: true, // Request counter trade discount
};
// Open trade with counter trade flag
const tx = await gnsMultiCollatDiamond.openTrade(
tradeStruct,
slippagePercent,
referrer
);
Note: The contract will validate if the trade actually qualifies as a counter trade. If not, it will be rejected. If the trade size is larger than the max skew limit, it will be reduced in size but still opened.
Pre-validation:
import { validateCounterTrade } from "@gainsnetworks/sdk/trade/counterTrade/validateCounterTrade";
// Check if trade qualifies as counter trade before submitting
const validation = validateCounterTrade(
isLong,
positionSizeCollateral,
leverage,
pairIndex,
tradingVariables
);
Detection (for existing trades):
// Check Trade struct field
const isCounterTrade = trade.isCounterTrade; // boolean field in v10 trades
5. Skew Price Impact
Price impact based on market skew (imbalance between long/short OI).
NOTE: The SDK offers wrapper utilities for open and close price impact which can be used to calculate all price impact data. More in SDK convenience functions.
Context Builder & Calculation:
import { buildSkewPriceImpactContext } from "@gainsnetwork/sdk/trade/priceImpact/skew/builder";
import { getTradeSkewPriceImpact } from "@gainsnetwork/sdk/trade/priceImpact/skew";
// Build context
const skewContext = buildSkewPriceImpactContext(
tradingVariables,
collateralIndex,
pairIndex
);
// Calculate skew price impact
const skewImpact = getTradeSkewPriceImpact(
isLong,
oraclePrice,
positionSizeToken,
skewContext
);
Helper functions:
import {
getNetSkewToken,
getNetSkewCollateral,
} from "@gainsnetwork/sdk/trade/priceImpact/skew";
// Get current market skew
const skewToken = getNetSkewToken(pairOiData);
const skewCollateral = getNetSkewCollateral(pairOiData, oraclePrice);
6. Market Max Skew Limits
Markets have maximum allowed skew to prevent excessive imbalance.
Check skew using computeOiValues:
import { computeOiValues } from "@gainsnetworks/sdk/markets/oi/converter";
// Compute current OI values including skew
const { skewToken } = computeOiValues(
pairOi,
oraclePrice / collateralPriceUsd // Convert to token price in collateral
);
// Get max skew from trading variables
const maxSkewCollateral =
tradingVariables.pairs[pairIndex]?.params?.maxSkewCollateral;
// Convert skewToken to collateral for comparison
const skewCollateral = Math.abs(skewToken) * (oraclePrice / collateralPriceUsd);
const skewExceeded = skewCollateral > maxSkewCollateral;
Note: For counter trade validation and position sizing, use validateCounterTrade
(see section 5).
7. Effective Leverage in Partial Updates
Partial position updates now validate against effective leverage (accounts for unrealized P&L).
Calculation:
import { getEffectiveLeverage } from "@gainsnetworks/sdk/trade/effectiveLeverage";
// Calculate effective leverage
const effectiveLeverage = getEffectiveLeverage(
trade.leverage,
trade.collateralAmount,
pnlCollateral
);
Validation Requirements:
For Position Increases (Partial Add):
Effective leverage must not exceed
pairMaxLeverage
Counter trades must not exceed
pairCounterTradeMaxLeverage
Adjusted initial leverage must be between 0.1x and max uint24 (~16,777x)
Pre-v10 trades cannot partial add
For Position Decreases (Partial Close):
No effective leverage maximum check
Only validates adjusted initial leverage (≥ 0.1x)
For Leverage Increases:
Same as position increases - effective leverage validated
For Leverage Decreases (Add Collateral):
Same as position decreases - no effective leverage check
// Example validation
const maxLeverage = isCounterTrade
? tradingVariables.pairs[pairIndex].maxLeverageCounterTrade
: tradingVariables.pairs[pairIndex].maxLeverage;
const isValid = effectiveLeverage <= maxLeverage;
const MIN_LEVERAGE = 0.1; // 0.1x minimum
8. Modified Borrowing Fees v1
Borrowing fees v1 now use dynamic OI (position size adjusted by current price vs entry price).
Context Builder & Calculation:
import { buildBorrowingV1Context } from "@gainsnetworks/sdk/trade/fees/borrowing/builder";
import { getBorrowingFee } from "@gainsnetworks/sdk/trade/fees/borrowing";
// Build borrowing v1 context
const borrowingV1Context = buildBorrowingV1Context(
tradingVariables,
collateralIndex,
currentBlock
);
// Calculate borrowing fee for a trade
const borrowingFee = getBorrowingFee(
positionSizeCollateral,
pairIndex,
isLong,
initialAccFees,
borrowingV1Context
);
Utility functions:
import { borrowingFeeUtils } from "@gainsnetworks/sdk/trade/fees/borrowing";
// Get pending accumulated fees for a pair
const pendingFees = borrowingFeeUtils.getPairPendingAccFees(
pairs,
pairGroups,
groups,
initialAccFees,
pairIndex,
currentBlock,
feePerBlockCaps
);
// Check if within max group OI
const withinLimit = borrowingFeeUtils.withinMaxGroupOi(
pairs,
pairGroups,
groups,
positionSizeCollateral,
pairIndex,
isLong
);
9. Modified Liquidation Calculations
Liquidation now accounts for pending fees and realized P&L.
Context Builder & Calculation:
import { buildLiquidationPriceContext } from "@gainsnetwork/sdk/trade/liquidation/builder";
import { getLiquidationPrice } from "@gainsnetwork/sdk/trade/liquidation";
// Build comprehensive context
const liquidationContext = buildLiquidationPriceContext(
tradingVariables,
tradeContainer,
{
currentBlock,
currentTimestamp,
currentPairPrice,
spreadP,
traderFeeMultiplier,
userPriceImpact,
}
);
// Calculate liquidation price
const liqPrice = getLiquidationPrice(trade, liquidationContext);
Additional functions:
import { getLiquidationPriceAfterPositionUpdate } from "@gainsnetwork/sdk/trade/liquidation";
// Calculate after position update
const newLiqPrice = getLiquidationPriceAfterPositionUpdate(
existingTrade,
existingLiquidationContext,
newCollateralAmount,
newLeverage
);
10. Modified PnL Calculations
Comprehensive PnL includes all v10 components: funding fees, borrowing fees, and realized P&L.
Context Builder & Calculation:
import { buildComprehensivePnlContext } from "@gainsnetwork/sdk/trade/pnl/builder";
import { getComprehensivePnl } from "@gainsnetwork/sdk/trade/pnl";
// Build context
const pnlContext = buildComprehensivePnlContext(
tradingVariables,
tradeContainer,
{
currentBlock,
currentTimestamp,
traderFeeMultiplier,
}
);
// Calculate comprehensive PnL
const pnl = getComprehensivePnl(
trade,
marketPrice,
executionPrice, // price after spreads/impacts
tradeInfo,
pnlContext
);
Helper functions:
import { getPnlPercent, getTradeValue } from "@gainsnetwork/sdk/trade/pnl";
// Calculate PnL percentage
const pnlPercent = getPnlPercent(openPrice, currentPrice, isLong, leverage);
// Get trade value (collateral + PnL)
const tradeValue = getTradeValue(collateralAmount, pnlCollateral);
11. New Trade Fields
v10 trades have additional fields that must be parsed and stored.
New fields in Trade struct:
interface Trade {
// ... existing fields ...
positionSizeToken: bigint; // Position size in token units (1e18 precision)
isCounterTrade: boolean; // Whether trade qualified for counter trade discount
}
12. V10 OI Tracking
OI is tracked separately for pre-v10 and post-v10 trades.
OI Functions:
import {
getPairTotalOisCollateral,
getPairTotalOisDynamicCollateral,
getPairV10OiTokenSkewCollateral,
getPairV10OiDynamicSkewCollateral,
} from "@gainsnetworks/sdk/markets/oi";
// Get total OI (pre-v10 only)
const staticOI = getPairTotalOisCollateral(pairOi);
// Get dynamic OI (pre-v10 + v10 adjusted by price)
const dynamicOI = getPairTotalOisDynamicCollateral(pairOi, oraclePrice);
// Get v10 skew in collateral
const skewCollateral = getPairV10OiTokenSkewCollateral(pairOi, oraclePrice);
// Get v10 dynamic skew
const dynamicSkew = getPairV10OiDynamicSkewCollateral(pairOi, oraclePrice);
Comprehensive OI Values:
import { computeOiValues } from "@gainsnetwork/sdk/markets/oi/converter";
// Get all computed OI values at once
const oiValues = computeOiValues(
pairOi,
oraclePrice / collateralPriceUsd // Convert to token price in collateral
);
Important notes:
Funding fees only apply to v10 OI
Skew calculations use v10 OI only
Max OI checks use combined OI (pre-v10 + v10)
Counter trade validation uses v10 skew
Market Price Concept
Market price is a v10 feature that applies to markets with funding fees and skew price impact. It represents the oracle price adjusted for current market skew.
Calculate Market Price:
import { getCurrentMarketPrice } from "@gainsnetworks/sdk/markets/price/marketPrice";
import { buildMarketPriceContext } from "@gainsnetworks/sdk/markets/price/builder";
// Build context for market price calculation
const marketPriceContext = buildMarketPriceContext(tradingVariables, pairIndex);
// Calculate market price from oracle price
const { marketPrice, skewImpactP } = getCurrentMarketPrice(
pairIndex,
oraclePrice,
marketPriceContext
);
SDK Wrapper Functions
The SDK provides high-level wrapper functions that combine multiple calculations for common operations.
Price Impact
Opening a Trade:
import { getTradeOpeningPriceImpact } from "@gainsnetwork/sdk/trade/priceImpact/open";
import { buildTradeOpeningPriceImpactContext } from "@gainsnetwork/sdk/trade/priceImpact/open/builder";
// Build context with all required data
const openContext = buildTradeOpeningPriceImpactContext(
tradingVariables,
collateralIndex,
pairIndex,
currentBlock
);
// Calculate total price impact and execution price
const openImpact = getTradeOpeningPriceImpact(
oraclePrice, // Always pass oracle price
isLong,
positionSizeCollateral,
leverage,
openContext
);
Understanding Price Impact Results:
// The function returns multiple price impact values:
const {
priceAfterImpact, // Final execution price
totalPriceImpactP, // Total impact from oracle price
totalPriceImpactPFromMarketPrice, // Total impact from market price
baseSkewPriceImpactP, // Market skew before trade
tradeSkewPriceImpactP, // Additional skew from this trade
totalSkewPriceImpactP, // Total skew impact (base + trade)
} = openImpact;
// For UI display:
// If showing market price: use totalPriceImpactPFromMarketPrice
// If showing oracle price: use totalPriceImpactP
Closing a Trade:
import { getTradeClosingPriceImpact } from "@gainsnetwork/sdk/trade/priceImpact/close";
import { buildTradeClosingPriceImpactContext } from "@gainsnetwork/sdk/trade/priceImpact/close/builder";
// Build context
const closeContext = buildTradeClosingPriceImpactContext(
tradingVariables,
tradeContainer,
currentBlock
);
// Calculate price impact for closing
const closeImpact = getTradeClosingPriceImpact(
trade,
oraclePrice, // Always pass oracle price
closeContext
);
// Similar to opening, returns multiple impact values
const {
priceAfterImpact,
tradeValueCollateral,
totalPriceImpactP, // From oracle price
totalPriceImpactPFromMarketPrice, // From market price
// ... other impact components
} = closeImpact;
Action Fees (Trading Fees)
Calculate Total Trading Fees:
import { getTotalTradeFeesCollateral } from "@gainsnetwork/sdk/trade/fees/trading";
import { buildTradingFeesContext } from "@gainsnetwork/sdk/trade/fees/trading/builder";
// Build context
const feesContext = buildTradingFeesContext(
tradingVariables,
collateralIndex,
pairIndex
);
// Calculate total fees
const totalFees = getTotalTradeFeesCollateral(
positionSizeCollateral,
isCounterTrade,
tradeTier,
feesContext
);
Get Detailed Fee Breakdown:
import { getTradeFeesCollateral } from "@gainsnetwork/sdk/trade/fees/trading";
// Get breakdown of all fee components
const feeBreakdown = getTradeFeesCollateral(
positionSizeCollateral,
pairOpenFeeP,
tradeTierMultiplier,
referralFeeP,
pairTriggerOrderFeeP,
pairOtcFeeP,
collateralPrecision
);
// Returns: referralFees, govFees, triggerFees, gnsOtcFees, gTokenFees
Calculate Pending Holding Fees:
import { getTradePendingHoldingFeesCollateral } from "@gainsnetwork/sdk/trade/fees/trading";
// Calculate all accumulated holding fees
const holdingFees = getTradePendingHoldingFeesCollateral(
trade,
currentBlock,
currentTimestamp,
oraclePrice,
collateralPrecision,
holdingFeesContext // combines funding + borrowing contexts
);
Summary
The SDK provides all necessary functions to integrate v10 features. Key patterns:
Use Context Builders: Most complex calculations require a context object built from trading variables
Transform Backend Data: Use
transformGlobalTradingVariables
andtransformGlobalTrades
before passing to SDK functionsHandle Pre-v10 Trades: Check
trade.contractsVersion
to determine if a trade uses v10 featuresDisplay Market Rates: Use functions in "Current Market Rates" section for market-wide statistics
Last updated
Was this helpful?