Add token estimates for liquidity quotes, group token resolution (#12)
- Add tokenEst to the increase/decrease liquidity quotes - Add group token resolution to minimize RPC calls when resolving ATAs
This commit is contained in:
parent
f3f0ce24e7
commit
f79dde5570
|
@ -14,6 +14,7 @@
|
|||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/decimal.js": "^7.4.0",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/mocha": "^9.0.0",
|
||||
|
|
|
@ -1667,6 +1667,21 @@
|
|||
"code": 6037,
|
||||
"name": "AmountInAboveMaximum",
|
||||
"msg": "Amount in above maximum threshold"
|
||||
},
|
||||
{
|
||||
"code": 6038,
|
||||
"name": "TickArraySequenceInvalidIndex",
|
||||
"msg": "Invalid index for tick array sequence"
|
||||
},
|
||||
{
|
||||
"code": 6039,
|
||||
"name": "AmountCalcOverflow",
|
||||
"msg": "Amount calculated overflows"
|
||||
},
|
||||
{
|
||||
"code": 6040,
|
||||
"name": "AmountRemainingOverflow",
|
||||
"msg": "Amount remaining overflows"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1667,6 +1667,21 @@ export type Whirlpool = {
|
|||
"code": 6037,
|
||||
"name": "AmountInAboveMaximum",
|
||||
"msg": "Amount in above maximum threshold"
|
||||
},
|
||||
{
|
||||
"code": 6038,
|
||||
"name": "TickArraySequenceInvalidIndex",
|
||||
"msg": "Invalid index for tick array sequence"
|
||||
},
|
||||
{
|
||||
"code": 6039,
|
||||
"name": "AmountCalcOverflow",
|
||||
"msg": "Amount calculated overflows"
|
||||
},
|
||||
{
|
||||
"code": 6040,
|
||||
"name": "AmountRemainingOverflow",
|
||||
"msg": "Amount remaining overflows"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -3340,6 +3355,21 @@ export const IDL: Whirlpool = {
|
|||
"code": 6037,
|
||||
"name": "AmountInAboveMaximum",
|
||||
"msg": "Amount in above maximum threshold"
|
||||
},
|
||||
{
|
||||
"code": 6038,
|
||||
"name": "TickArraySequenceInvalidIndex",
|
||||
"msg": "Invalid index for tick array sequence"
|
||||
},
|
||||
{
|
||||
"code": 6039,
|
||||
"name": "AmountCalcOverflow",
|
||||
"msg": "Amount calculated overflows"
|
||||
},
|
||||
{
|
||||
"code": 6040,
|
||||
"name": "AmountRemainingOverflow",
|
||||
"msg": "Amount remaining overflows"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import {
|
|||
AddressUtil,
|
||||
deriveATA,
|
||||
Percentage,
|
||||
resolveOrCreateATA,
|
||||
resolveOrCreateATAs,
|
||||
TransactionBuilder,
|
||||
ZERO,
|
||||
} from "@orca-so/common-sdk";
|
||||
|
@ -168,7 +168,13 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
invariant(TickUtil.checkTickInBounds(tickLower), "tickLower is out of bounds.");
|
||||
invariant(TickUtil.checkTickInBounds(tickUpper), "tickUpper is out of bounds.");
|
||||
|
||||
const { liquidityAmount: liquidity, tokenMaxA, tokenMaxB } = liquidityInput;
|
||||
const {
|
||||
liquidityAmount: liquidity,
|
||||
tokenMaxA,
|
||||
tokenMaxB,
|
||||
tokenEstA,
|
||||
tokenEstB,
|
||||
} = liquidityInput;
|
||||
|
||||
invariant(liquidity.gt(new u64(0)), "liquidity must be greater than zero");
|
||||
|
||||
|
@ -215,20 +221,18 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
);
|
||||
txBuilder.addInstruction(positionIx).addSigner(positionMintKeypair);
|
||||
|
||||
const { address: tokenOwnerAccountA, ...tokenOwnerAccountAIx } = await resolveOrCreateATA(
|
||||
const [ataA, ataB] = await resolveOrCreateATAs(
|
||||
this.ctx.connection,
|
||||
sourceWallet,
|
||||
whirlpool.tokenMintA,
|
||||
() => this.fetcher.getAccountRentExempt(),
|
||||
tokenMaxA
|
||||
);
|
||||
const { address: tokenOwnerAccountB, ...tokenOwnerAccountBIx } = await resolveOrCreateATA(
|
||||
this.ctx.connection,
|
||||
sourceWallet,
|
||||
whirlpool.tokenMintB,
|
||||
() => this.fetcher.getAccountRentExempt(),
|
||||
tokenMaxB
|
||||
[
|
||||
{ tokenMint: whirlpool.tokenMintA, wrappedSolAmountIn: tokenMaxA },
|
||||
{ tokenMint: whirlpool.tokenMintB, wrappedSolAmountIn: tokenMaxB },
|
||||
],
|
||||
() => this.fetcher.getAccountRentExempt()
|
||||
);
|
||||
const { address: tokenOwnerAccountA, ...tokenOwnerAccountAIx } = ataA;
|
||||
const { address: tokenOwnerAccountB, ...tokenOwnerAccountBIx } = ataB;
|
||||
|
||||
txBuilder.addInstruction(tokenOwnerAccountAIx);
|
||||
txBuilder.addInstruction(tokenOwnerAccountBIx);
|
||||
|
||||
|
@ -257,6 +261,8 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
liquidityAmount: liquidity,
|
||||
tokenMaxA,
|
||||
tokenMaxB,
|
||||
tokenEstA,
|
||||
tokenEstB,
|
||||
whirlpool: this.address,
|
||||
positionAuthority: positionWallet,
|
||||
position: positionPda.publicKey,
|
||||
|
@ -311,18 +317,16 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
const txBuilder = new TransactionBuilder(this.ctx.provider);
|
||||
|
||||
const resolvedAssociatedTokenAddresses: Record<string, PublicKey> = {};
|
||||
const { address: tokenOwnerAccountA, ...createTokenOwnerAccountAIx } = await resolveOrCreateATA(
|
||||
const [ataA, ataB] = await resolveOrCreateATAs(
|
||||
this.ctx.connection,
|
||||
destinationWallet,
|
||||
whirlpool.tokenMintA,
|
||||
() => this.fetcher.getAccountRentExempt()
|
||||
);
|
||||
const { address: tokenOwnerAccountB, ...createTokenOwnerAccountBIx } = await resolveOrCreateATA(
|
||||
this.ctx.connection,
|
||||
destinationWallet,
|
||||
whirlpool.tokenMintB,
|
||||
[{ tokenMint: whirlpool.tokenMintA }, { tokenMint: whirlpool.tokenMintB }],
|
||||
() => this.fetcher.getAccountRentExempt()
|
||||
);
|
||||
|
||||
const { address: tokenOwnerAccountA, ...createTokenOwnerAccountAIx } = ataA;
|
||||
const { address: tokenOwnerAccountB, ...createTokenOwnerAccountBIx } = ataB;
|
||||
|
||||
txBuilder.addInstruction(createTokenOwnerAccountAIx).addInstruction(createTokenOwnerAccountBIx);
|
||||
resolvedAssociatedTokenAddresses[whirlpool.tokenMintA.toBase58()] = tokenOwnerAccountA;
|
||||
resolvedAssociatedTokenAddresses[whirlpool.tokenMintB.toBase58()] = tokenOwnerAccountB;
|
||||
|
@ -351,6 +355,8 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
liquidityAmount: decreaseLiqQuote.liquidityAmount,
|
||||
tokenMinA: decreaseLiqQuote.tokenMinA,
|
||||
tokenMinB: decreaseLiqQuote.tokenMinB,
|
||||
tokenEstA: decreaseLiqQuote.tokenEstA,
|
||||
tokenEstB: decreaseLiqQuote.tokenEstB,
|
||||
whirlpool: position.whirlpool,
|
||||
positionAuthority: positionWallet,
|
||||
position: positionAddress,
|
||||
|
@ -390,22 +396,20 @@ export class WhirlpoolImpl implements Whirlpool {
|
|||
const whirlpool = this.data;
|
||||
const txBuilder = new TransactionBuilder(this.ctx.provider);
|
||||
|
||||
const { address: tokenOwnerAccountA, ...tokenOwnerAccountAIx } = await resolveOrCreateATA(
|
||||
const [ataA, ataB] = await resolveOrCreateATAs(
|
||||
this.ctx.connection,
|
||||
wallet,
|
||||
whirlpool.tokenMintA,
|
||||
() => this.fetcher.getAccountRentExempt(),
|
||||
aToB ? estimatedAmountIn : ZERO
|
||||
[
|
||||
{ tokenMint: whirlpool.tokenMintA, wrappedSolAmountIn: aToB ? estimatedAmountIn : ZERO },
|
||||
{ tokenMint: whirlpool.tokenMintB, wrappedSolAmountIn: !aToB ? estimatedAmountIn : ZERO },
|
||||
],
|
||||
() => this.fetcher.getAccountRentExempt()
|
||||
);
|
||||
txBuilder.addInstruction(tokenOwnerAccountAIx);
|
||||
|
||||
const { address: tokenOwnerAccountB, ...tokenOwnerAccountBIx } = await resolveOrCreateATA(
|
||||
this.ctx.connection,
|
||||
wallet,
|
||||
whirlpool.tokenMintB,
|
||||
() => this.fetcher.getAccountRentExempt(),
|
||||
!aToB ? estimatedAmountIn : ZERO
|
||||
);
|
||||
const { address: tokenOwnerAccountA, ...tokenOwnerAccountAIx } = ataA;
|
||||
const { address: tokenOwnerAccountB, ...tokenOwnerAccountBIx } = ataB;
|
||||
|
||||
txBuilder.addInstruction(tokenOwnerAccountAIx);
|
||||
txBuilder.addInstruction(tokenOwnerAccountBIx);
|
||||
|
||||
const targetSqrtPriceLimitX64 = sqrtPriceLimit || this.getDefaultSqrtPriceLimit(aToB);
|
||||
|
|
|
@ -42,6 +42,8 @@ export type DecreaseLiquidityParams = {
|
|||
export type DecreaseLiquidityInput = {
|
||||
tokenMinA: BN;
|
||||
tokenMinB: BN;
|
||||
tokenEstA: BN;
|
||||
tokenEstB: BN;
|
||||
liquidityAmount: BN;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ export type IncreaseLiquidityParams = {
|
|||
export type IncreaseLiquidityInput = {
|
||||
tokenMaxA: u64;
|
||||
tokenMaxB: u64;
|
||||
tokenEstA: u64;
|
||||
tokenEstB: u64;
|
||||
liquidityAmount: u64;
|
||||
};
|
||||
|
||||
|
|
|
@ -106,15 +106,14 @@ function quotePositionBelowRange(param: DecreaseLiquidityQuoteParam): DecreaseLi
|
|||
const sqrtPriceLowerX64 = PriceMath.tickIndexToSqrtPriceX64(tickLowerIndex);
|
||||
const sqrtPriceUpperX64 = PriceMath.tickIndexToSqrtPriceX64(tickUpperIndex);
|
||||
|
||||
const minTokenA = adjustForSlippage(
|
||||
getTokenAFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, false),
|
||||
slippageTolerance,
|
||||
false
|
||||
);
|
||||
const tokenEstA = getTokenAFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, false);
|
||||
const tokenMinA = adjustForSlippage(tokenEstA, slippageTolerance, false);
|
||||
|
||||
return {
|
||||
tokenMinA: minTokenA,
|
||||
tokenMinA,
|
||||
tokenMinB: ZERO,
|
||||
tokenEstA,
|
||||
tokenEstB: ZERO,
|
||||
liquidityAmount: liquidity,
|
||||
};
|
||||
}
|
||||
|
@ -126,20 +125,16 @@ function quotePositionInRange(param: DecreaseLiquidityQuoteParam): DecreaseLiqui
|
|||
const sqrtPriceLowerX64 = PriceMath.tickIndexToSqrtPriceX64(tickLowerIndex);
|
||||
const sqrtPriceUpperX64 = PriceMath.tickIndexToSqrtPriceX64(tickUpperIndex);
|
||||
|
||||
const minTokenA = adjustForSlippage(
|
||||
getTokenAFromLiquidity(liquidity, sqrtPriceX64, sqrtPriceUpperX64, false),
|
||||
slippageTolerance,
|
||||
false
|
||||
);
|
||||
const minTokenB = adjustForSlippage(
|
||||
getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceX64, false),
|
||||
slippageTolerance,
|
||||
false
|
||||
);
|
||||
const tokenEstA = getTokenAFromLiquidity(liquidity, sqrtPriceX64, sqrtPriceUpperX64, false);
|
||||
const tokenMinA = adjustForSlippage(tokenEstA, slippageTolerance, false);
|
||||
const tokenEstB = getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceX64, false);
|
||||
const tokenMinB = adjustForSlippage(tokenEstB, slippageTolerance, false);
|
||||
|
||||
return {
|
||||
tokenMinA: minTokenA,
|
||||
tokenMinB: minTokenB,
|
||||
tokenMinA,
|
||||
tokenMinB,
|
||||
tokenEstA,
|
||||
tokenEstB,
|
||||
liquidityAmount: liquidity,
|
||||
};
|
||||
}
|
||||
|
@ -150,15 +145,14 @@ function quotePositionAboveRange(param: DecreaseLiquidityQuoteParam): DecreaseLi
|
|||
const sqrtPriceLowerX64 = PriceMath.tickIndexToSqrtPriceX64(tickLowerIndex);
|
||||
const sqrtPriceUpperX64 = PriceMath.tickIndexToSqrtPriceX64(tickUpperIndex);
|
||||
|
||||
const minTokenB = adjustForSlippage(
|
||||
getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, false),
|
||||
slippageTolerance,
|
||||
false
|
||||
);
|
||||
const tokenEstB = getTokenBFromLiquidity(liquidity, sqrtPriceLowerX64, sqrtPriceUpperX64, false);
|
||||
const tokenMinB = adjustForSlippage(tokenEstB, slippageTolerance, false);
|
||||
|
||||
return {
|
||||
tokenMinA: ZERO,
|
||||
tokenMinB: minTokenB,
|
||||
tokenMinB,
|
||||
tokenEstA: ZERO,
|
||||
tokenEstB,
|
||||
liquidityAmount: liquidity,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -129,6 +129,8 @@ function quotePositionBelowRange(param: IncreaseLiquidityQuoteParam): IncreaseLi
|
|||
return {
|
||||
tokenMaxA: ZERO,
|
||||
tokenMaxB: ZERO,
|
||||
tokenEstA: ZERO,
|
||||
tokenEstB: ZERO,
|
||||
liquidityAmount: ZERO,
|
||||
};
|
||||
}
|
||||
|
@ -143,16 +145,19 @@ function quotePositionBelowRange(param: IncreaseLiquidityQuoteParam): IncreaseLi
|
|||
false
|
||||
);
|
||||
|
||||
const maxTokenA = adjustForSlippage(
|
||||
getTokenAFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceUpperX64, true),
|
||||
slippageTolerance,
|
||||
const tokenEstA = getTokenAFromLiquidity(
|
||||
liquidityAmount,
|
||||
sqrtPriceLowerX64,
|
||||
sqrtPriceUpperX64,
|
||||
true
|
||||
);
|
||||
const maxTokenB = ZERO;
|
||||
const tokenMaxA = adjustForSlippage(tokenEstA, slippageTolerance, true);
|
||||
|
||||
return {
|
||||
tokenMaxA: maxTokenA,
|
||||
tokenMaxB: maxTokenB,
|
||||
tokenMaxA,
|
||||
tokenMaxB: ZERO,
|
||||
tokenEstA,
|
||||
tokenEstB: ZERO,
|
||||
liquidityAmount,
|
||||
};
|
||||
}
|
||||
|
@ -172,30 +177,32 @@ function quotePositionInRange(param: IncreaseLiquidityQuoteParam): IncreaseLiqui
|
|||
const sqrtPriceLowerX64 = PriceMath.tickIndexToSqrtPriceX64(tickLowerIndex);
|
||||
const sqrtPriceUpperX64 = PriceMath.tickIndexToSqrtPriceX64(tickUpperIndex);
|
||||
|
||||
let [tokenAmountA, tokenAmountB] = tokenMintA.equals(inputTokenMint)
|
||||
let [tokenEstA, tokenEstB] = tokenMintA.equals(inputTokenMint)
|
||||
? [inputTokenAmount, undefined]
|
||||
: [undefined, inputTokenAmount];
|
||||
|
||||
let liquidityAmount: BN;
|
||||
|
||||
if (tokenAmountA) {
|
||||
liquidityAmount = getLiquidityFromTokenA(tokenAmountA, sqrtPriceX64, sqrtPriceUpperX64, false);
|
||||
tokenAmountA = getTokenAFromLiquidity(liquidityAmount, sqrtPriceX64, sqrtPriceUpperX64, true);
|
||||
tokenAmountB = getTokenBFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceX64, true);
|
||||
} else if (tokenAmountB) {
|
||||
liquidityAmount = getLiquidityFromTokenB(tokenAmountB, sqrtPriceLowerX64, sqrtPriceX64, false);
|
||||
tokenAmountA = getTokenAFromLiquidity(liquidityAmount, sqrtPriceX64, sqrtPriceUpperX64, true);
|
||||
tokenAmountB = getTokenBFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceX64, true);
|
||||
if (tokenEstA) {
|
||||
liquidityAmount = getLiquidityFromTokenA(tokenEstA, sqrtPriceX64, sqrtPriceUpperX64, false);
|
||||
tokenEstA = getTokenAFromLiquidity(liquidityAmount, sqrtPriceX64, sqrtPriceUpperX64, true);
|
||||
tokenEstB = getTokenBFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceX64, true);
|
||||
} else if (tokenEstB) {
|
||||
liquidityAmount = getLiquidityFromTokenB(tokenEstB, sqrtPriceLowerX64, sqrtPriceX64, false);
|
||||
tokenEstA = getTokenAFromLiquidity(liquidityAmount, sqrtPriceX64, sqrtPriceUpperX64, true);
|
||||
tokenEstB = getTokenBFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceX64, true);
|
||||
} else {
|
||||
throw new Error("invariant violation");
|
||||
}
|
||||
|
||||
const maxTokenA = adjustForSlippage(tokenAmountA, slippageTolerance, true);
|
||||
const maxTokenB = adjustForSlippage(tokenAmountB, slippageTolerance, true);
|
||||
const tokenMaxA = adjustForSlippage(tokenEstA, slippageTolerance, true);
|
||||
const tokenMaxB = adjustForSlippage(tokenEstB, slippageTolerance, true);
|
||||
|
||||
return {
|
||||
tokenMaxA: maxTokenA,
|
||||
tokenMaxB: maxTokenB,
|
||||
tokenMaxA,
|
||||
tokenMaxB,
|
||||
tokenEstA: tokenEstA!,
|
||||
tokenEstB: tokenEstB!,
|
||||
liquidityAmount,
|
||||
};
|
||||
}
|
||||
|
@ -214,6 +221,8 @@ function quotePositionAboveRange(param: IncreaseLiquidityQuoteParam): IncreaseLi
|
|||
return {
|
||||
tokenMaxA: ZERO,
|
||||
tokenMaxB: ZERO,
|
||||
tokenEstA: ZERO,
|
||||
tokenEstB: ZERO,
|
||||
liquidityAmount: ZERO,
|
||||
};
|
||||
}
|
||||
|
@ -227,16 +236,19 @@ function quotePositionAboveRange(param: IncreaseLiquidityQuoteParam): IncreaseLi
|
|||
false
|
||||
);
|
||||
|
||||
const maxTokenA = ZERO;
|
||||
const maxTokenB = adjustForSlippage(
|
||||
getTokenBFromLiquidity(liquidityAmount, sqrtPriceLowerX64, sqrtPriceUpperX64, true),
|
||||
slippageTolerance,
|
||||
const tokenEstB = getTokenBFromLiquidity(
|
||||
liquidityAmount,
|
||||
sqrtPriceLowerX64,
|
||||
sqrtPriceUpperX64,
|
||||
true
|
||||
);
|
||||
const tokenMaxB = adjustForSlippage(tokenEstB, slippageTolerance, true);
|
||||
|
||||
return {
|
||||
tokenMaxA: maxTokenA,
|
||||
tokenMaxB: maxTokenB,
|
||||
tokenMaxA: ZERO,
|
||||
tokenMaxB,
|
||||
tokenEstA: ZERO,
|
||||
tokenEstB,
|
||||
liquidityAmount,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -703,6 +703,13 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.3.0"
|
||||
|
||||
"@types/bn.js@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68"
|
||||
integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/connect@^3.4.33":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
|
|
Loading…
Reference in New Issue