Skip to content
This repository was archived by the owner on Jul 17, 2023. It is now read-only.

Commit f3de5c2

Browse files
author
scuba
authored
Pool add getDepositQuote, getWithdrawQuote api's (#47)
* Pool add getDepositQuote, getWithdrawQuote api's * remove unused functions * getQuote slippage should be optional * percentage input, constraint token * comments update * change types * special case: handle SOL in getUserTokenCount * decimal bug fix * address comments * comment update
1 parent 503c244 commit f3de5c2

File tree

2 files changed

+189
-2
lines changed

2 files changed

+189
-2
lines changed

src/model/orca/pool/orca-pool.ts

+139
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import {
1919
TransactionPayload,
2020
Percentage,
2121
resolveOrCreateAssociatedTokenAddress,
22+
ZERO,
23+
DepositQuote,
24+
WithdrawQuote,
25+
DecimalUtil,
2226
} from "../../../public";
2327
import {
2428
createApprovalInstruction,
@@ -49,6 +53,10 @@ export class OrcaPoolImpl implements OrcaPool {
4953
return this.poolParams.tokens[tokenId];
5054
}
5155

56+
public getPoolTokenMint(): PublicKey {
57+
return this.poolParams.poolTokenMint;
58+
}
59+
5260
public async getLPBalance(owner: PublicKey): Promise<OrcaU64> {
5361
const address = await deriveAssociatedTokenAddress(owner, this.poolParams.poolTokenMint);
5462

@@ -184,6 +192,57 @@ export class OrcaPoolImpl implements OrcaPool {
184192
.build();
185193
}
186194

195+
public async getDepositQuote(
196+
maxTokenAIn: Decimal | OrcaU64,
197+
maxTokenBIn: Decimal | OrcaU64,
198+
slippage?: Decimal
199+
): Promise<DepositQuote> {
200+
const slippageTolerance =
201+
slippage === undefined ? defaultSlippagePercentage : Percentage.fromDecimal(slippage);
202+
203+
const maxTokenAIn_U64 = U64Utils.toTokenU64(maxTokenAIn, this.getTokenA(), "maxTokenAIn");
204+
const maxTokenBIn_U64 = U64Utils.toTokenU64(maxTokenBIn, this.getTokenB(), "maxTokenBIn");
205+
206+
const { inputTokenCount: tokenAAmount, outputTokenCount: tokenBAmount } = await getTokenCount(
207+
this.connection,
208+
this.poolParams,
209+
this.getTokenA(),
210+
this.getTokenB()
211+
);
212+
const lpSupply = await this.getLPSupply();
213+
214+
if (tokenAAmount.eq(ZERO) || tokenBAmount.eq(ZERO)) {
215+
return {
216+
minPoolTokenAmountOut: OrcaU64.fromU64(ZERO, lpSupply.scale),
217+
maxTokenAIn: OrcaU64.fromU64(maxTokenAIn_U64, this.getTokenA().scale),
218+
maxTokenBIn: OrcaU64.fromU64(maxTokenBIn_U64, this.getTokenB().scale),
219+
};
220+
}
221+
222+
const poolTokenAmountWithA = maxTokenAIn_U64
223+
.mul(slippageTolerance.denominator)
224+
.mul(lpSupply.toU64())
225+
.div(tokenAAmount)
226+
.div(slippageTolerance.numerator.add(slippageTolerance.denominator));
227+
228+
const poolTokenAmountWithB = maxTokenBIn_U64
229+
.mul(slippageTolerance.denominator)
230+
.mul(lpSupply.toU64())
231+
.div(tokenBAmount)
232+
.div(slippageTolerance.numerator.add(slippageTolerance.denominator));
233+
234+
// Pick the smaller value of the two to calculate the minimum poolTokenAmount out
235+
const minPoolTokenAmountOut_U64 = poolTokenAmountWithA.gt(poolTokenAmountWithB)
236+
? poolTokenAmountWithB
237+
: poolTokenAmountWithA;
238+
239+
return {
240+
minPoolTokenAmountOut: OrcaU64.fromU64(minPoolTokenAmountOut_U64, lpSupply.scale),
241+
maxTokenAIn: OrcaU64.fromU64(maxTokenAIn_U64, this.getTokenA().scale),
242+
maxTokenBIn: OrcaU64.fromU64(maxTokenBIn_U64, this.getTokenB().scale),
243+
};
244+
}
245+
187246
public async deposit(
188247
owner: Keypair | PublicKey,
189248
maxTokenAIn: Decimal | OrcaU64,
@@ -270,6 +329,86 @@ export class OrcaPoolImpl implements OrcaPool {
270329
.build();
271330
}
272331

332+
public async getWithdrawQuote(
333+
withdrawTokenAmount: Decimal | OrcaU64,
334+
withdrawTokenMint: PublicKey,
335+
slippage?: Decimal
336+
): Promise<WithdrawQuote> {
337+
const slippageTolerance =
338+
slippage === undefined ? defaultSlippagePercentage : Percentage.fromDecimal(slippage);
339+
340+
const lpSupply = await this.getLPSupply();
341+
const { inputTokenCount: tokenAAmount, outputTokenCount: tokenBAmount } = await getTokenCount(
342+
this.connection,
343+
this.poolParams,
344+
this.getTokenA(),
345+
this.getTokenB()
346+
);
347+
348+
// withdrawTokenAmount needs represent amounts for one of the following: poolTokenAmount, tokenAAmount, or tokenBAmount
349+
// determine which token this amount represents, then calculate poolTokenIn_U64
350+
let poolTokenIn_U64 = ZERO;
351+
if (withdrawTokenMint.equals(this.getPoolTokenMint())) {
352+
poolTokenIn_U64 = U64Utils.toPoolU64(
353+
withdrawTokenAmount,
354+
this.poolParams,
355+
"withdrawTokenAmount"
356+
);
357+
} else if (
358+
withdrawTokenMint.equals(this.getTokenA().mint) ||
359+
withdrawTokenMint.equals(this.getTokenB().mint)
360+
) {
361+
const token = withdrawTokenMint.equals(this.getTokenA().mint)
362+
? this.getTokenA()
363+
: this.getTokenB();
364+
const totalAmount = token.mint.equals(this.getTokenA().mint) ? tokenAAmount : tokenBAmount;
365+
366+
const numerator =
367+
withdrawTokenAmount instanceof OrcaU64
368+
? withdrawTokenAmount.toDecimal()
369+
: withdrawTokenAmount;
370+
const denominator = DecimalUtil.fromU64(totalAmount, token.scale);
371+
const poolTokenIn = lpSupply.toDecimal().div(denominator).mul(numerator);
372+
poolTokenIn_U64 = U64Utils.toPoolU64(poolTokenIn, this.poolParams, "poolTokenIn");
373+
} else {
374+
throw new Error(
375+
`Unable to get withdraw quote with an invalid withdrawTokenMint ${withdrawTokenMint}`
376+
);
377+
}
378+
379+
if (poolTokenIn_U64.eq(ZERO)) {
380+
return {
381+
maxPoolTokenAmountIn: OrcaU64.fromU64(ZERO, lpSupply.scale),
382+
minTokenAOut: OrcaU64.fromU64(ZERO, this.getTokenA().scale),
383+
minTokenBOut: OrcaU64.fromU64(ZERO, this.getTokenB().scale),
384+
};
385+
}
386+
387+
const minTokenAOut = new OrcaU64(
388+
poolTokenIn_U64
389+
.mul(slippageTolerance.denominator)
390+
.mul(tokenAAmount)
391+
.div(lpSupply.toU64())
392+
.div(slippageTolerance.numerator.add(slippageTolerance.denominator)),
393+
this.getTokenA().scale
394+
);
395+
396+
const minTokenBOut = new OrcaU64(
397+
poolTokenIn_U64
398+
.mul(slippageTolerance.denominator)
399+
.mul(tokenBAmount)
400+
.div(lpSupply.toU64())
401+
.div(slippageTolerance.numerator.add(slippageTolerance.denominator)),
402+
this.getTokenB().scale
403+
);
404+
405+
return {
406+
maxPoolTokenAmountIn: OrcaU64.fromU64(poolTokenIn_U64, lpSupply.scale),
407+
minTokenAOut,
408+
minTokenBOut,
409+
};
410+
}
411+
273412
public async withdraw(
274413
owner: Keypair | PublicKey,
275414
poolTokenAmountIn: Decimal | OrcaU64,

src/public/pools/types.ts

+50-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ import Decimal from "decimal.js";
33
import { OrcaU64 } from "..";
44
import { TransactionPayload } from "../utils";
55

6+
export type DepositQuote = {
7+
minPoolTokenAmountOut: OrcaU64;
8+
maxTokenAIn: OrcaU64;
9+
maxTokenBIn: OrcaU64;
10+
};
11+
12+
export type WithdrawQuote = {
13+
minTokenAOut: OrcaU64;
14+
minTokenBOut: OrcaU64;
15+
maxPoolTokenAmountIn: OrcaU64;
16+
};
17+
618
/**
719
* Allows interactions with an Orca liquidity pool.
820
*/
@@ -19,6 +31,12 @@ export type OrcaPool = {
1931
*/
2032
getTokenB: () => OrcaPoolToken;
2133

34+
/**
35+
* Query the mint public key for the pool token of this pool.
36+
* @returns Returns the tokenMint public key of this pool
37+
*/
38+
getPoolTokenMint: () => PublicKey;
39+
2240
/**
2341
* Query the balance for an user address
2442
* @param wallet The public key for the user.
@@ -39,13 +57,13 @@ export type OrcaPool = {
3957
*
4058
* @param inputTokenId The token you want to trade from
4159
* @param inputAmount The amount of token you would to trade
42-
* @param slippage The slippage in percentage you are willing to take in this trade
60+
* @param slippage An optional slippage in percentage you are willing to take in this trade (default: 0.1%)
4361
* @return Returns a quote on the exchanged token based on the input token amount
4462
*/
4563
getQuote: (
4664
inputToken: OrcaToken,
4765
inputAmount: Decimal | OrcaU64,
48-
slippage: Decimal
66+
slippage?: Decimal
4967
) => Promise<Quote>;
5068

5169
/**
@@ -69,6 +87,20 @@ export type OrcaPool = {
6987
minimumAmountOut: Decimal | OrcaU64
7088
) => Promise<TransactionPayload>;
7189

90+
/**
91+
* Get suggested pool token deposit amount based on required constraints on maximum tokenA amount and maximum tokenB amount
92+
*
93+
* @param maxTokenAIn The maximum amount of tokenA to deposit in exchange for pool token
94+
* @param maxTokenBIn The maximum amount of tokenB to deposit in exchange for pool token
95+
* @param slippage An optional slippage in percentage you are willing to take in deposit (default: 0.1%)
96+
* @return Returns the input for deposit
97+
*/
98+
getDepositQuote: (
99+
maxTokenAIn: Decimal | OrcaU64,
100+
maxTokenBIn: Decimal | OrcaU64,
101+
slippage?: Decimal
102+
) => Promise<DepositQuote>;
103+
72104
/**
73105
* Perform a deposit: send tokenA and tokenB, and receive a poolToken in return.
74106
* Fee for the transaction will be paid by the owner's wallet.
@@ -90,6 +122,22 @@ export type OrcaPool = {
90122
minPoolTokenAmountOut: Decimal | OrcaU64
91123
) => Promise<TransactionPayload>;
92124

125+
/**
126+
* Get suggested withdraw token amounts based on required withdraw amount of the pool token / one of the paired tokens
127+
*
128+
* Throws error if withdrawTokenMint does not equal tokenMint of tokenA, tokenB, or poolToken of this pool
129+
*
130+
* @param withdrawTokenAmount The amount of tokens to withdraw in terms of tokenA amount, tokenB amount, or poolToken amount
131+
* @param withdrawTokenMint The token mint public key of tied to withdrawTokenAmount. It should be the mint of tokenA, tokenB, or poolToken
132+
* @param slippage An optional slippage in percentage you are willing to take in withdraw (default: 0.1%)
133+
* @return Returns the input for withdraw
134+
*/
135+
getWithdrawQuote: (
136+
withdrawTokenAmount: Decimal | OrcaU64,
137+
withdrawTokenMint: PublicKey,
138+
slippage?: Decimal
139+
) => Promise<WithdrawQuote>;
140+
93141
/**
94142
* Perform a withdraw: send poolToken, and receive tokenA and tokenB in return.
95143
* Fee for the transaction will be paid by the owner's wallet.

0 commit comments

Comments
 (0)