diff --git a/src/components/Synthetics/GmList/MintableAmount.tsx b/src/components/Synthetics/GmList/MintableAmount.tsx index 19d1b4c889..bf42528488 100644 --- a/src/components/Synthetics/GmList/MintableAmount.tsx +++ b/src/components/Synthetics/GmList/MintableAmount.tsx @@ -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"; @@ -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] ); @@ -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] ); diff --git a/src/components/Synthetics/MarketStats/MarketStatsWithComposition.tsx b/src/components/Synthetics/MarketStats/MarketStatsWithComposition.tsx index 67d95393cb..51c84ed5a2 100644 --- a/src/components/Synthetics/MarketStats/MarketStatsWithComposition.tsx +++ b/src/components/Synthetics/MarketStats/MarketStatsWithComposition.tsx @@ -10,7 +10,7 @@ import { getMarketIndexName, getGlvOrMarketAddress, getMarketPoolName, - getMaxPoolUsd, + getStrictestMaxPoolUsdForDeposit, getPoolUsdWithoutPnl, } from "domain/synthetics/markets"; import { TokenData, TokensData, convertToTokenAmount, convertToUsd } from "domain/synthetics/tokens"; @@ -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))})` : "", ], [ @@ -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))})` : "", ], [ diff --git a/src/domain/synthetics/markets/utils.ts b/src/domain/synthetics/markets/utils.ts index 4f9a662d67..ce5d1562b1 100644 --- a/src/domain/synthetics/markets/utils.ts +++ b/src/domain/synthetics/markets/utils.ts @@ -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; @@ -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; diff --git a/src/domain/synthetics/trade/types.ts b/src/domain/synthetics/trade/types.ts index 4b5237fa02..1ffbaba043 100644 --- a/src/domain/synthetics/trade/types.ts +++ b/src/domain/synthetics/trade/types.ts @@ -167,6 +167,7 @@ export type SwapStats = { isWrap: boolean; isUnwrap: boolean; isOutLiquidity?: boolean; + isOutCapacity?: boolean; swapFeeAmount: bigint; swapFeeUsd: bigint; priceImpactDeltaUsd: bigint; diff --git a/src/domain/synthetics/trade/utils/swapRouting.ts b/src/domain/synthetics/trade/utils/swapRouting.ts index 53cdb695af..a21d5b9d27 100644 --- a/src/domain/synthetics/trade/utils/swapRouting.ts +++ b/src/domain/synthetics/trade/utils/swapRouting.ts @@ -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[] { @@ -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; @@ -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, }; diff --git a/src/domain/synthetics/trade/utils/swapStats.ts b/src/domain/synthetics/trade/utils/swapStats.ts index ddcdb2eaef..44b1550c9d 100644 --- a/src/domain/synthetics/trade/utils/swapStats.ts +++ b/src/domain/synthetics/trade/utils/swapStats.ts @@ -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"; @@ -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" @@ -345,5 +350,6 @@ export function getSwapStats(p: { amountOut, usdOut, isOutLiquidity, + isOutCapacity, }; } diff --git a/src/pages/SyntheticsStats/SyntheticsStats.tsx b/src/pages/SyntheticsStats/SyntheticsStats.tsx index c7204e8ee1..a18992e3ad 100644 --- a/src/pages/SyntheticsStats/SyntheticsStats.tsx +++ b/src/pages/SyntheticsStats/SyntheticsStats.tsx @@ -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 @@ -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 ( -