Add resolveATA option for Position's increase_liquidity (#31)

- Add an option to auto-generate ATA to perform increase_liquidity for Whirlpool's position class
This commit is contained in:
meep 2022-06-29 15:22:14 -04:00 committed by GitHub
parent 537306c096
commit 4416732e33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 11 deletions

View File

@ -45,7 +45,9 @@ export class PositionImpl implements Position {
async increaseLiquidity(
liquidityInput: IncreaseLiquidityInput,
sourceWallet?: Address,
positionWallet?: Address
positionWallet?: Address,
resolveATA?: boolean,
ataPayer?: Address
) {
const sourceWalletKey = sourceWallet
? AddressUtil.toPubKey(sourceWallet)
@ -53,6 +55,7 @@ export class PositionImpl implements Position {
const positionWalletKey = positionWallet
? AddressUtil.toPubKey(positionWallet)
: this.ctx.wallet.publicKey;
const ataPayerKey = ataPayer ? AddressUtil.toPubKey(ataPayer) : this.ctx.wallet.publicKey;
const whirlpool = await this.fetcher.getPool(this.data.whirlpool, true);
if (!whirlpool) {
@ -60,8 +63,31 @@ export class PositionImpl implements Position {
}
const txBuilder = new TransactionBuilder(this.ctx.provider);
const tokenOwnerAccountA = await deriveATA(sourceWalletKey, whirlpool.tokenMintA);
const tokenOwnerAccountB = await deriveATA(sourceWalletKey, whirlpool.tokenMintB);
let tokenOwnerAccountA: PublicKey;
let tokenOwnerAccountB: PublicKey;
if (resolveATA) {
const [ataA, ataB] = await resolveOrCreateATAs(
this.ctx.connection,
sourceWalletKey,
[
{ tokenMint: whirlpool.tokenMintA, wrappedSolAmountIn: liquidityInput.tokenMaxA },
{ tokenMint: whirlpool.tokenMintB, wrappedSolAmountIn: liquidityInput.tokenMaxB },
],
() => this.fetcher.getAccountRentExempt(),
ataPayerKey
);
const { address: ataAddrA, ...tokenOwnerAccountAIx } = ataA!;
const { address: ataAddrB, ...tokenOwnerAccountBIx } = ataB!;
tokenOwnerAccountA = ataAddrA;
tokenOwnerAccountB = ataAddrB;
txBuilder.addInstruction(tokenOwnerAccountAIx);
txBuilder.addInstruction(tokenOwnerAccountBIx);
} else {
tokenOwnerAccountA = await deriveATA(sourceWalletKey, whirlpool.tokenMintA);
tokenOwnerAccountB = await deriveATA(sourceWalletKey, whirlpool.tokenMintB);
}
const positionTokenAccount = await deriveATA(positionWalletKey, this.data.positionMint);
const increaseIx = increaseLiquidityIx(this.ctx.program, {

View File

@ -207,15 +207,21 @@ export interface Position {
/**
* Deposit additional tokens into this postiion.
* The wallet must contain the position token and the necessary token A & B to complete the deposit.
* If `wallet` is provided, the wallet owners have to sign this transaction.
* If `positionWallet` are `wallet` is provided, the wallet owners have to sign this transaction.
*
* @param liquidityInput - input that defines the desired liquidity amount and maximum tokens willing to be to deposited.
* @param wallet - the wallet to withdraw tokens to deposit into the position. If null, the WhirlpoolContext wallet is used.
* @param positionWallet - optional - the wallet to that houses the position token. If null, the WhirlpoolContext wallet is used.
* @param resolveATA - optional - if true, add instructions to create associated token accounts for tokenA,B for the destinationWallet if necessary.
* @param ataPayer - optional - wallet that will fund the creation of the new associated token accounts
* @return the transaction that will deposit the tokens into the position when executed.
*/
increaseLiquidity: (
liquidityInput: IncreaseLiquidityInput,
wallet?: Address
wallet?: Address,
positionWallet?: Address,
resolveATA?: boolean,
ataPayer?: Address
) => Promise<TransactionBuilder>;
/**

View File

@ -51,7 +51,7 @@ describe("position-impl", () => {
);
// [Action] Initialize Tick Arrays
const initTickArrayTx = await pool.initTickArrayForTicks([lowerTick, upperTick]);
const initTickArrayTx = (await pool.initTickArrayForTicks([lowerTick, upperTick]))!;
await initTickArrayTx.buildAndExecute();
// [Action] Create a position at price 89, 120 with 50 token A
@ -108,7 +108,7 @@ describe("position-impl", () => {
assert.equal(postWithdrawData.liquidity.toString(), expectedPostWithdrawLiquidity.toString());
});
it("decrease liquidity on position with a different destination, position wallet", async () => {
it("increase & decrease liquidity on position with a different destination, position wallet", async () => {
const { poolInitInfo } = await initTestPool(
ctx,
TickSpacing.Standard,
@ -137,7 +137,7 @@ describe("position-impl", () => {
);
// [Action] Initialize Tick Arrays
const initTickArrayTx = await pool.initTickArrayForTicks([lowerTick, upperTick]);
const initTickArrayTx = (await pool.initTickArrayForTicks([lowerTick, upperTick]))!;
await initTickArrayTx.buildAndExecute();
// [Action] Create a position at price 89, 120 with 50 token A
@ -194,6 +194,36 @@ describe("position-impl", () => {
);
await transfer(provider, walletPositionTokenAccount, newOwnerPositionTokenAccount, 1);
// Mint to this other wallet and increase more tokens
await mintTokensToTestAccount(
ctx.provider,
poolInitInfo.tokenMintA,
10_500_000_000,
poolInitInfo.tokenMintB,
10_500_000_000,
otherWallet.publicKey
);
const increaseQuoteFromOtherWallet = increaseLiquidityQuoteByInputToken(
poolInitInfo.tokenMintB,
new Decimal(80),
lowerTick,
upperTick,
Percentage.fromFraction(1, 100),
pool
);
await (
await position.increaseLiquidity(
increaseQuoteFromOtherWallet,
otherWallet.publicKey,
otherWallet.publicKey,
true
)
)
.addSigner(otherWallet)
.buildAndExecute();
const postSecondIncreaseData = await position.refreshData();
// Withdraw liquidity into another wallet
const destinationWallet = anchor.web3.Keypair.generate();
await (
@ -208,7 +238,7 @@ describe("position-impl", () => {
.buildAndExecute();
const postWithdrawData = await position.refreshData();
const expectedPostWithdrawLiquidity = postIncreaseData.liquidity.sub(
const expectedPostWithdrawLiquidity = postSecondIncreaseData.liquidity.sub(
decrease_quote.liquidityAmount
);
assert.equal(postWithdrawData.liquidity.toString(), expectedPostWithdrawLiquidity.toString());

View File

@ -28,7 +28,7 @@ import {
} from "@orca-so/common-sdk";
import { mintTokensToTestAccount } from "../../utils/test-builders";
describe.only("whirlpool-impl", () => {
describe("whirlpool-impl", () => {
const provider = anchor.Provider.local();
anchor.setProvider(anchor.Provider.env());
const program = anchor.workspace.Whirlpool;

View File

@ -237,7 +237,6 @@ export async function initPosition(
upperTick,
quote,
sourceWalletKey,
sourceWalletKey,
ctx.wallet.publicKey
);