Skip to content

Commit

Permalink
Merge pull request #1505 from gmx-io/hotfix-fix-swap-caps
Browse files Browse the repository at this point in the history
Hotfix: Fix swap caps
  • Loading branch information
divhead authored Jan 14, 2025
2 parents ecc5bce + abe6b2c commit 427da58
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 33 deletions.
6 changes: 3 additions & 3 deletions src/components/Synthetics/GmList/MintableAmount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { formatTokenAmount, formatTokenAmountWithUsd, formatUsd } from "lib/numb
import StatsTooltipRow from "components/StatsTooltip/StatsTooltipRow";
import TooltipWithPortal from "components/Tooltip/TooltipWithPortal";

import { getMaxPoolUsd, getPoolUsdWithoutPnl, GlvOrMarketInfo } from "domain/synthetics/markets";
import { getPoolUsdWithoutPnl, getStrictestMaxPoolUsdForDeposit, GlvOrMarketInfo } from "domain/synthetics/markets";
import { TokenData } from "domain/synthetics/tokens";

import { isGlvInfo } from "domain/synthetics/markets/glv";
Expand Down Expand Up @@ -49,7 +49,7 @@ export function MintableAmount({
longToken.decimals
)
: "-",
`(${formatUsd(getPoolUsdWithoutPnl(market, true, "midPrice"))} / ${formatUsd(getMaxPoolUsd(market, true))})`,
`(${formatUsd(getPoolUsdWithoutPnl(market, true, "midPrice"))} / ${formatUsd(getStrictestMaxPoolUsdForDeposit(market, true))})`,
],
[isGlv, longToken, market, mintableInfo]
);
Expand All @@ -66,7 +66,7 @@ export function MintableAmount({
shortToken.decimals
)
: "-",
`(${formatUsd(getPoolUsdWithoutPnl(market, false, "midPrice"))} / ${formatUsd(getMaxPoolUsd(market, false))})`,
`(${formatUsd(getPoolUsdWithoutPnl(market, false, "midPrice"))} / ${formatUsd(getStrictestMaxPoolUsdForDeposit(market, false))})`,
],
[isGlv, market, mintableInfo, shortToken]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
getMarketIndexName,
getGlvOrMarketAddress,
getMarketPoolName,
getMaxPoolUsd,
getStrictestMaxPoolUsdForDeposit,
getPoolUsdWithoutPnl,
} from "domain/synthetics/markets";
import { TokenData, TokensData, convertToTokenAmount, convertToUsd } from "domain/synthetics/tokens";
Expand Down Expand Up @@ -118,7 +118,7 @@ export function MarketStatsWithComposition(p: Props) {
longToken?.decimals
),
marketInfo
? `(${formatUsd(getPoolUsdWithoutPnl(marketInfo, true, "midPrice"))} / ${formatUsd(getMaxPoolUsd(marketInfo, true))})`
? `(${formatUsd(getPoolUsdWithoutPnl(marketInfo, true, "midPrice"))} / ${formatUsd(getStrictestMaxPoolUsdForDeposit(marketInfo, true))})`
: "",
],
[
Expand All @@ -142,7 +142,7 @@ export function MarketStatsWithComposition(p: Props) {
shortToken?.decimals
),
marketInfo
? `(${formatUsd(getPoolUsdWithoutPnl(marketInfo, false, "midPrice"))} / ${formatUsd(getMaxPoolUsd(marketInfo, false))})`
? `(${formatUsd(getPoolUsdWithoutPnl(marketInfo, false, "midPrice"))} / ${formatUsd(getStrictestMaxPoolUsdForDeposit(marketInfo, false))})`
: "",
],
[
Expand Down
29 changes: 24 additions & 5 deletions src/domain/synthetics/markets/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,13 @@ export function getTotalAccruedFundingUsd(positions: PositionInfo[]) {

function getDepositCapacityAmount(marketInfo: MarketInfo, isLong: boolean) {
const poolAmount = isLong ? marketInfo.longPoolAmount : marketInfo.shortPoolAmount;
const maxPoolAmount = getMaxPoolAmount(marketInfo, isLong);
const maxPoolAmount = getStrictestMaxPoolAmountForDeposit(marketInfo, isLong);
const capacityAmount = maxPoolAmount - poolAmount;

return bigMath.max(0n, capacityAmount);
}

export function getMaxPoolAmount(marketInfo: MarketInfo, isLong: boolean) {
export function getStrictestMaxPoolAmountForDeposit(marketInfo: MarketInfo, isLong: boolean) {
const maxPoolUsdForDeposit = isLong ? marketInfo.maxLongPoolUsdForDeposit : marketInfo.maxShortPoolUsdForDeposit;
const maxPoolAmount = isLong ? marketInfo.maxLongPoolAmount : marketInfo.maxShortPoolAmount;
const token = isLong ? marketInfo.longToken : marketInfo.shortToken;
Expand All @@ -422,16 +422,35 @@ export function getMaxPoolAmount(marketInfo: MarketInfo, isLong: boolean) {
return bigMath.min(maxPoolAmount, maxPoolAmountForDeposit);
}

export function getMaxPoolUsd(marketInfo: MarketInfo, isLong: boolean) {
export function getStrictestMaxPoolUsdForDeposit(marketInfo: MarketInfo, isLong: boolean) {
const token = isLong ? marketInfo.longToken : marketInfo.shortToken;
const maxPoolAmount = getMaxPoolAmount(marketInfo, isLong);
const maxPoolAmount = getStrictestMaxPoolAmountForDeposit(marketInfo, isLong);

return convertToUsd(maxPoolAmount, token.decimals, getMidPrice(token.prices))!;
}

export function getMaxPoolUsdForSwap(marketInfo: MarketInfo, isLong: boolean) {
const token = isLong ? marketInfo.longToken : marketInfo.shortToken;
const maxPoolAmount = isLong ? marketInfo.maxLongPoolAmount : marketInfo.maxShortPoolAmount;

return convertToUsd(maxPoolAmount, token.decimals, getMidPrice(token.prices))!;
}

export function getSwapCapacityUsd(marketInfo: MarketInfo, isLong: boolean) {
const poolAmount = isLong ? marketInfo.longPoolAmount : marketInfo.shortPoolAmount;
const maxPoolAmount = isLong ? marketInfo.maxLongPoolAmount : marketInfo.maxShortPoolAmount;

const capacityAmount = maxPoolAmount - poolAmount;
const token = isLong ? marketInfo.longToken : marketInfo.shortToken;

const capacityUsd = convertToUsd(capacityAmount, token.decimals, getMidPrice(token.prices))!;

return capacityUsd;
}

export function getDepositCapacityUsd(marketInfo: MarketInfo, isLong: boolean) {
const poolUsd = getPoolUsdWithoutPnl(marketInfo, isLong, "midPrice");
const maxPoolUsd = getMaxPoolUsd(marketInfo, isLong);
const maxPoolUsd = getStrictestMaxPoolUsdForDeposit(marketInfo, isLong);

const capacityUsd = maxPoolUsd - poolUsd;

Expand Down
1 change: 1 addition & 0 deletions src/domain/synthetics/trade/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export type SwapStats = {
isWrap: boolean;
isUnwrap: boolean;
isOutLiquidity?: boolean;
isOutCapacity?: boolean;
swapFeeAmount: bigint;
swapFeeUsd: bigint;
priceImpactDeltaUsd: bigint;
Expand Down
21 changes: 18 additions & 3 deletions src/domain/synthetics/trade/utils/swapRouting.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { getAvailableUsdLiquidityForCollateral, MarketInfo, MarketsInfoData } from "domain/synthetics/markets";
import {
getAvailableUsdLiquidityForCollateral,
getSwapCapacityUsd,
MarketInfo,
MarketsInfoData,
} from "domain/synthetics/markets";
import { MarketEdge, MarketsGraph, SwapEstimator, SwapRoute } from "../types";
import { getMaxSwapPathLiquidity, getSwapStats } from "./swapStats";
import { SWAP_GRAPH_MAX_MARKETS_PER_TOKEN } from "config/markets";
import { bigMath } from "lib/bigmath";

// limit the number of markets to most N=SWAP_GRAPH_MAX_MARKETS_PER_TOKEN liquid markets for each collateral
export function limitMarketsPerTokens(markets: MarketInfo[]): MarketInfo[] {
Expand Down Expand Up @@ -30,8 +36,16 @@ export function limitMarketsPerTokens(markets: MarketInfo[]): MarketInfo[] {

const sortedMarkets = markets.sort((m1, m2) => {
const liq1 = getAvailableUsdLiquidityForCollateral(m1, m1.longTokenAddress === tokenAddress);
const cap1 = getSwapCapacityUsd(m1, m1.longTokenAddress === tokenAddress);

const limit1 = bigMath.min(liq1, cap1);

const liq2 = getAvailableUsdLiquidityForCollateral(m2, m2.longTokenAddress === tokenAddress);
return Number(liq2 - liq1);
const cap2 = getSwapCapacityUsd(m2, m2.longTokenAddress === tokenAddress);

const limit2 = bigMath.min(liq2, cap2);

return Number(limit2 - limit1);
});

let marketsPerTokenCount = 0;
Expand Down Expand Up @@ -102,9 +116,10 @@ export const createSwapEstimator = (marketsInfoData: MarketsInfoData): SwapEstim
});

const isOutLiquidity = swapStats?.isOutLiquidity;
const isOutCapacity = swapStats?.isOutCapacity;
const usdOut = swapStats?.usdOut;

if (usdOut === undefined || isOutLiquidity) {
if (usdOut === undefined || isOutLiquidity || isOutCapacity) {
return {
usdOut: 0n,
};
Expand Down
8 changes: 7 additions & 1 deletion src/domain/synthetics/trade/utils/swapStats.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { NATIVE_TOKEN_ADDRESS } from "sdk/configs/tokens";
import { getSwapFee } from "domain/synthetics/fees";
import {
MarketInfo,
MarketsInfoData,
getAvailableUsdLiquidityForCollateral,
getOppositeCollateral,
getSwapCapacityUsd,
getTokenPoolType,
} from "domain/synthetics/markets";
import { convertToTokenAmount, convertToUsd } from "domain/synthetics/tokens";
import { ethers } from "ethers";
import { getByKey } from "lib/objects";
import { NATIVE_TOKEN_ADDRESS } from "sdk/configs/tokens";
import { applySwapImpactWithCap, getPriceImpactForSwap } from "../../fees/utils/priceImpact";
import { SwapPathStats, SwapStats } from "../types";

Expand Down Expand Up @@ -323,6 +324,10 @@ export function getSwapStats(p: {

amountOut = convertToTokenAmount(usdOut, tokenOut.decimals, priceOut)!;

const capacityUsd = getSwapCapacityUsd(marketInfo, getTokenPoolType(marketInfo, tokenInAddress) === "long");

const isOutCapacity = capacityUsd < usdInAfterFees;

const liquidity = getAvailableUsdLiquidityForCollateral(
marketInfo,
getTokenPoolType(marketInfo, tokenOutAddress) === "long"
Expand All @@ -345,5 +350,6 @@ export function getSwapStats(p: {
amountOut,
usdOut,
isOutLiquidity,
isOutCapacity,
};
}
69 changes: 51 additions & 18 deletions src/pages/SyntheticsStats/SyntheticsStats.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import { ethers } from "ethers";
import { useChainId } from "lib/chains";
import { CHART_PERIODS } from "lib/legacy";
import { ethers } from "ethers";
import { expandDecimals, formatAmount, formatUsd, PRECISION } from "lib/numbers";

import cx from "classnames";
import { DownloadAsCsv } from "components/DownloadAsCsv/DownloadAsCsv";
import { ShareBar } from "components/ShareBar/ShareBar";
import StatsTooltipRow from "components/StatsTooltip/StatsTooltipRow";
import TooltipWithPortal from "components/Tooltip/TooltipWithPortal";
import { FACTOR_TO_PERCENT_MULTIPLIER_BIGINT } from "config/factors";
import { format } from "date-fns";
import { getBorrowingFactorPerPeriod, getFundingFactorPerPeriod, getPriceImpactUsd } from "domain/synthetics/fees";
import {
MarketInfo,
getUsedLiquidity,
getAvailableUsdLiquidityForCollateral,
getCappedPoolPnl,
getMarketIndexName,
getMarketNetPnl,
getMarketPnl,
getMarketPoolName,
getMaxOpenInterestUsd,
getMaxPoolUsdForSwap,
getMaxReservedUsd,
getPoolUsdWithoutPnl,
getReservedUsd,
getStrictestMaxPoolUsdForDeposit,
getUsedLiquidity,
MarketInfo,
useMarketsInfoRequest,
getMarketNetPnl,
getMarketPnl,
getCappedPoolPnl,
getPoolUsdWithoutPnl,
} from "domain/synthetics/markets";
import { useKinkModelMarketsRates } from "domain/synthetics/markets/useKinkModelMarketsRates";
import { usePositionsConstantsRequest } from "domain/synthetics/positions";
import { convertToUsd, getMidPrice } from "domain/synthetics/tokens";
import "./SyntheticsStats.scss";
import TooltipWithPortal from "components/Tooltip/TooltipWithPortal";
import { DownloadAsCsv } from "components/DownloadAsCsv/DownloadAsCsv";
import { format } from "date-fns";
import { getPlusOrMinusSymbol, getPositiveOrNegativeClass } from "lib/utils";
import { useKinkModelMarketsRates } from "domain/synthetics/markets/useKinkModelMarketsRates";
import { bigMath } from "lib/bigmath";
import { formatAmountHuman } from "lib/numbers";
import { FACTOR_TO_PERCENT_MULTIPLIER_BIGINT } from "config/factors";
import { getPlusOrMinusSymbol, getPositiveOrNegativeClass } from "lib/utils";
import "./SyntheticsStats.scss";

function pow(bn: bigint, exponent: bigint) {
// this is just aproximation
Expand Down Expand Up @@ -366,17 +368,48 @@ export function SyntheticsStats() {

function renderPoolCapCell(isLong: boolean) {
const poolAmount = isLong ? market.longPoolAmount : market.shortPoolAmount;
const maxPoolUsdForSwap = getMaxPoolUsdForSwap(market, isLong);
const maxPoolUsdForDeposit = isLong
? market.maxLongPoolUsdForDeposit
: market.maxShortPoolUsdForDeposit;
const maxPoolAmount = isLong ? market.maxLongPoolAmount : market.maxShortPoolAmount;
const maxPoolUsd = getStrictestMaxPoolUsdForDeposit(market, isLong);
const token = isLong ? market.longToken : market.shortToken;
const poolUsd = convertToUsd(poolAmount, token.decimals, getMidPrice(token.prices));

return (
<div className="cell">
{formatAmountHuman(poolAmount, token.decimals)} {token.symbol} / {formatUsd(maxPoolUsdForDeposit)}{" "}
<ShareBar share={poolUsd} total={maxPoolUsdForDeposit} warningThreshold={90} />
</div>
<TooltipWithPortal
handle={
<div className="cell">
{formatAmountHuman(poolAmount, token.decimals)} {token.symbol} / {formatUsd(maxPoolUsd)}{" "}
<ShareBar share={poolUsd} total={maxPoolUsd} warningThreshold={90} />
</div>
}
renderContent={() => (
<>
<StatsTooltipRow
label="Pool Amount Capacity"
showDollar={false}
value={`${formatAmountHuman(poolAmount, token.decimals)} ${token.symbol} / ${formatAmountHuman(maxPoolAmount, token.decimals)} ${token.symbol}`}
/>
<StatsTooltipRow
label="Pool USD Capacity (Swap)"
showDollar={false}
value={`${formatUsd(poolUsd)} / ${formatUsd(maxPoolUsdForSwap)}`}
/>
<StatsTooltipRow
label="Deposit USD Capacity"
showDollar={false}
value={`${formatUsd(poolUsd)} / ${formatUsd(maxPoolUsdForDeposit)}`}
/>
<StatsTooltipRow
label="Strictest Deposit USD Capacity"
showDollar={false}
value={`${formatUsd(poolUsd)} / ${formatUsd(maxPoolUsd)}`}
/>
</>
)}
/>
);
}

Expand Down

0 comments on commit 427da58

Please sign in to comment.