Skip to content

Commit

Permalink
feat(v3-sdk): add insufficient liquidity handling
Browse files Browse the repository at this point in the history
Improved insufficient liquidity error handling by updating error checks and throw conditions. Modified return values in `v3Swap` to include `amountSpecifiedRemaining` and made necessary adjustments in pool and trade logic to reflect these changes.
  • Loading branch information
shuhuiluo committed Dec 10, 2024
1 parent ff2be9a commit 9168b71
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 12 deletions.
22 changes: 20 additions & 2 deletions sdks/v3-sdk/src/entities/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BigintIsh, CurrencyAmount, Price, Token } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import invariant from 'tiny-invariant'
import { FACTORY_ADDRESS, FeeAmount, TICK_SPACINGS } from '../constants'
import { NEGATIVE_ONE, Q192 } from '../internalConstants'
import { NEGATIVE_ONE, Q192, ZERO } from '../internalConstants'
import { computePoolAddress } from '../utils/computePoolAddress'
import { v3Swap } from '../utils/v3swap'
import { TickMath } from '../utils/tickMath'
Expand Down Expand Up @@ -154,11 +154,17 @@ export class Pool {
const zeroForOne = inputAmount.currency.equals(this.token0)

const {
amountSpecifiedRemaining,
amountCalculated: outputAmount,
sqrtRatioX96,
liquidity,
tickCurrent,
} = await this.swap(zeroForOne, inputAmount.quotient, sqrtPriceLimitX96)

if (!JSBI.equal(amountSpecifiedRemaining, ZERO) && !sqrtPriceLimitX96) {
throw new Error('INSUFFICIENT_LIQUIDITY')
}

const outputToken = zeroForOne ? this.token1 : this.token0
return [
CurrencyAmount.fromRawAmount(outputToken, JSBI.multiply(outputAmount, NEGATIVE_ONE)),
Expand All @@ -181,11 +187,17 @@ export class Pool {
const zeroForOne = outputAmount.currency.equals(this.token1)

const {
amountSpecifiedRemaining,
amountCalculated: inputAmount,
sqrtRatioX96,
liquidity,
tickCurrent,
} = await this.swap(zeroForOne, JSBI.multiply(outputAmount.quotient, NEGATIVE_ONE), sqrtPriceLimitX96)

if (!JSBI.equal(amountSpecifiedRemaining, ZERO) && !sqrtPriceLimitX96) {
throw new Error('INSUFFICIENT_LIQUIDITY')
}

const inputToken = zeroForOne ? this.token0 : this.token1
return [
CurrencyAmount.fromRawAmount(inputToken, inputAmount),
Expand All @@ -207,7 +219,13 @@ export class Pool {
zeroForOne: boolean,
amountSpecified: JSBI,
sqrtPriceLimitX96?: JSBI
): Promise<{ amountCalculated: JSBI; sqrtRatioX96: JSBI; liquidity: JSBI; tickCurrent: number }> {
): Promise<{
amountSpecifiedRemaining: JSBI
amountCalculated: JSBI
sqrtRatioX96: JSBI
liquidity: JSBI
tickCurrent: number
}> {
return v3Swap(
JSBI.BigInt(this.fee),
this.sqrtRatioX96,
Expand Down
12 changes: 6 additions & 6 deletions sdks/v3-sdk/src/entities/trade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,20 +815,20 @@ describe('Trade', () => {
expect(result[0].swaps[0].route.tokenPath).toEqual([token0, token2])
})

it.skip('insufficient liquidity', () => {
const result = Trade.bestTradeExactOut(
it('insufficient liquidity', async () => {
const result = await Trade.bestTradeExactOut(
[pool_0_1, pool_0_2, pool_1_2],
token0,
CurrencyAmount.fromRawAmount(token2, 1200)
CurrencyAmount.fromRawAmount(token2, 120000)
)
expect(result).toHaveLength(0)
})

it.skip('insufficient liquidity in one pool but not the other', () => {
const result = Trade.bestTradeExactOut(
it('insufficient liquidity in one pool but not the other', async () => {
const result = await Trade.bestTradeExactOut(
[pool_0_1, pool_0_2, pool_1_2],
token0,
CurrencyAmount.fromRawAmount(token2, JSBI.BigInt(1050))
CurrencyAmount.fromRawAmount(token2, JSBI.BigInt(105000))
)
expect(result).toHaveLength(1)
})
Expand Down
6 changes: 3 additions & 3 deletions sdks/v3-sdk/src/entities/trade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,8 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
try {
;[amountOut] = await pool.getOutputAmount(amountIn)
} catch (error) {
// input too low
if ((error as any).isInsufficientInputAmountError) {
// not enough liquidity in this pool
if ((error as Error).message === 'INSUFFICIENT_LIQUIDITY') {
continue
}
throw error
Expand Down Expand Up @@ -599,7 +599,7 @@ export class Trade<TInput extends Currency, TOutput extends Currency, TTradeType
;[amountIn] = await pool.getInputAmount(amountOut)
} catch (error) {
// not enough liquidity in this pool
if ((error as any).isInsufficientReservesError) {
if ((error as Error).message === 'INSUFFICIENT_LIQUIDITY') {
continue
}
throw error
Expand Down
9 changes: 8 additions & 1 deletion sdks/v3-sdk/src/utils/v3swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export async function v3Swap(
zeroForOne: boolean,
amountSpecified: JSBI,
sqrtPriceLimitX96?: JSBI
): Promise<{ amountCalculated: JSBI; sqrtRatioX96: JSBI; liquidity: JSBI; tickCurrent: number }> {
): Promise<{
amountSpecifiedRemaining: JSBI
tickCurrent: number
liquidity: JSBI
sqrtRatioX96: JSBI
amountCalculated: JSBI
}> {
if (!sqrtPriceLimitX96)
sqrtPriceLimitX96 = zeroForOne
? JSBI.add(TickMath.MIN_SQRT_RATIO, ONE)
Expand Down Expand Up @@ -119,6 +125,7 @@ export async function v3Swap(
}

return {
amountSpecifiedRemaining: state.amountSpecifiedRemaining,
amountCalculated: state.amountCalculated,
sqrtRatioX96: state.sqrtPriceX96,
liquidity: state.liquidity,
Expand Down

0 comments on commit 9168b71

Please sign in to comment.