Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/true-pens-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@orca-so/whirlpools-sdk": patch
"@orca-so/whirlpools-program": patch
"@orca-so/whirlpools-rust-client": patch
"@orca-so/whirlpools-client": patch
---

Add event emission feature
Original file line number Diff line number Diff line change
Expand Up @@ -1052,4 +1052,87 @@ describe("decrease_liquidity", () => {
/0x7d1/, // A has one constraint was violated
);
});

it("emit LiquidityDecreased event", async () => {
const liquidityAmount = new anchor.BN(1_250_000);
const tickLower = 7168,
tickUpper = 8960;
const fixture = await new WhirlpoolTestFixture(ctx).init({
tickSpacing: TickSpacing.Standard,
initialSqrtPrice: MathUtil.toX64(new Decimal(1.48)),
positions: [
{
tickLowerIndex: tickLower,
tickUpperIndex: tickUpper,
liquidityAmount,
},
],
});
const { poolInitInfo, tokenAccountA, tokenAccountB, positions } =
fixture.getInfos();
const { whirlpoolPda, tokenVaultAKeypair, tokenVaultBKeypair } =
poolInitInfo;
const poolBefore = (await fetcher.getPool(
whirlpoolPda.publicKey,
IGNORE_CACHE,
)) as WhirlpoolData;

const removalQuote = decreaseLiquidityQuoteByLiquidityWithParams({
liquidity: new anchor.BN(1_000_000),
sqrtPrice: poolBefore.sqrtPrice,
slippageTolerance: Percentage.fromFraction(1, 100),
tickCurrentIndex: poolBefore.tickCurrentIndex,
tickLowerIndex: tickLower,
tickUpperIndex: tickUpper,
tokenExtensionCtx: await TokenExtensionUtil.buildTokenExtensionContext(
fetcher,
poolBefore,
IGNORE_CACHE,
),
});

// event verification
let eventVerified = false;
let detectedSignature = null;
const listener = ctx.program.addEventListener(
"LiquidityDecreased",
(event, _slot, signature) => {
detectedSignature = signature;
// verify
assert.ok(event.whirlpool.equals(whirlpoolPda.publicKey));
assert.ok(event.position.equals(positions[0].publicKey));
assert.ok(event.liquidity.eq(removalQuote.liquidityAmount));
assert.ok(event.tickLowerIndex === tickLower);
assert.ok(event.tickUpperIndex === tickUpper);
assert.ok(event.tokenAAmount.eq(removalQuote.tokenEstA));
assert.ok(event.tokenBAmount.eq(removalQuote.tokenEstB));
assert.ok(event.tokenATransferFee.isZero()); // v1 doesn't handle TransferFee extension
assert.ok(event.tokenBTransferFee.isZero()); // v1 doesn't handle TransferFee extension
eventVerified = true;
},
);

const signature = await toTx(
ctx,
WhirlpoolIx.decreaseLiquidityIx(ctx.program, {
...removalQuote,
whirlpool: whirlpoolPda.publicKey,
positionAuthority: provider.wallet.publicKey,
position: positions[0].publicKey,
positionTokenAccount: positions[0].tokenAccount,
tokenOwnerAccountA: tokenAccountA,
tokenOwnerAccountB: tokenAccountB,
tokenVaultA: tokenVaultAKeypair.publicKey,
tokenVaultB: tokenVaultBKeypair.publicKey,
tickArrayLower: positions[0].tickArrayLower,
tickArrayUpper: positions[0].tickArrayUpper,
}),
).buildAndExecute();

await sleep(2000);
assert.equal(signature, detectedSignature);
assert.ok(eventVerified);

ctx.program.removeEventListener(listener);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -1381,4 +1381,73 @@ describe("increase_liquidity", () => {
/0x7d1/, // A has one constraint was violated
);
});

it("emit LiquidityIncreased event", async () => {
const currTick = 0;
const tickLowerIndex = -1280,
tickUpperIndex = 1280;
const fixture = await new WhirlpoolTestFixture(ctx).init({
tickSpacing: TickSpacing.Standard,
positions: [{ tickLowerIndex, tickUpperIndex, liquidityAmount: ZERO_BN }],
initialSqrtPrice: PriceMath.tickIndexToSqrtPriceX64(currTick),
});
const { poolInitInfo, positions, tokenAccountA, tokenAccountB } =
fixture.getInfos();
const { whirlpoolPda } = poolInitInfo;
const positionInitInfo = positions[0];

const tokenAmount = toTokenAmount(167_000, 167_000);
const liquidityAmount = PoolUtil.estimateLiquidityFromTokenAmounts(
currTick,
tickLowerIndex,
tickUpperIndex,
tokenAmount,
);

// event verification
let eventVerified = false;
let detectedSignature = null;
const listener = ctx.program.addEventListener(
"LiquidityIncreased",
(event, _slot, signature) => {
detectedSignature = signature;
// verify
assert.ok(event.whirlpool.equals(whirlpoolPda.publicKey));
assert.ok(event.position.equals(positionInitInfo.publicKey));
assert.ok(event.liquidity.eq(liquidityAmount));
assert.ok(event.tickLowerIndex === tickLowerIndex);
assert.ok(event.tickUpperIndex === tickUpperIndex);
assert.ok(event.tokenAAmount.eq(tokenAmount.tokenA));
assert.ok(event.tokenBAmount.eq(tokenAmount.tokenB));
assert.ok(event.tokenATransferFee.isZero()); // v1 doesn't handle TransferFee extension
assert.ok(event.tokenBTransferFee.isZero()); // v1 doesn't handle TransferFee extension
eventVerified = true;
},
);

const signature = await toTx(
ctx,
WhirlpoolIx.increaseLiquidityIx(ctx.program, {
liquidityAmount,
tokenMaxA: tokenAmount.tokenA,
tokenMaxB: tokenAmount.tokenB,
whirlpool: whirlpoolPda.publicKey,
positionAuthority: provider.wallet.publicKey,
position: positionInitInfo.publicKey,
positionTokenAccount: positionInitInfo.tokenAccount,
tokenOwnerAccountA: tokenAccountA,
tokenOwnerAccountB: tokenAccountB,
tokenVaultA: poolInitInfo.tokenVaultAKeypair.publicKey,
tokenVaultB: poolInitInfo.tokenVaultBKeypair.publicKey,
tickArrayLower: positionInitInfo.tickArrayLower,
tickArrayUpper: positionInitInfo.tickArrayUpper,
}),
).buildAndExecute();

await sleep(2000);
assert.equal(signature, detectedSignature);
assert.ok(eventVerified);

ctx.program.removeEventListener(listener);
});
});
122 changes: 122 additions & 0 deletions legacy-sdk/whirlpool/tests/integration/initialize_pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ZERO_BN,
asyncAssertTokenVault,
createMint,
sleep,
systemTransferTx,
} from "../utils";
import { defaultConfirmOptions } from "../utils/const";
Expand All @@ -28,6 +29,12 @@ import {
initFeeTier,
initTestPool,
} from "../utils/init-utils";
import {
createInitializeMintInstruction,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { Keypair, SystemProgram } from "@solana/web3.js";
import { PoolUtil } from "../../dist/utils/public/pool-utils";

describe("initialize_pool", () => {
const provider = anchor.AnchorProvider.local(
Expand Down Expand Up @@ -485,4 +492,119 @@ describe("initialize_pool", () => {
assert.equal(whirlpool.whirlpoolBump, validBump);
assert.notEqual(whirlpool.whirlpoolBump, invalidBump);
});

it("emit PoolInitialized event", async () => {
const { poolInitInfo } = await buildTestPoolParams(
ctx,
TickSpacing.Standard,
);

const whirlpoolsConfig = poolInitInfo.whirlpoolsConfig;
const tickSpacing = poolInitInfo.tickSpacing;

// initialize mint with various decimals
const tokenXKeypair = Keypair.generate();
const tokenYKeypair = Keypair.generate();
const [tokenAKeypair, tokenBKeypair] =
PoolUtil.compareMints(tokenXKeypair.publicKey, tokenYKeypair.publicKey) <
0
? [tokenXKeypair, tokenYKeypair]
: [tokenYKeypair, tokenXKeypair];
const decimalsA = 7;
const decimalsB = 11;
await toTx(ctx, {
instructions: [
SystemProgram.createAccount({
fromPubkey: ctx.wallet.publicKey,
newAccountPubkey: tokenAKeypair.publicKey,
space: 82,
lamports:
await ctx.provider.connection.getMinimumBalanceForRentExemption(82),
programId: TOKEN_PROGRAM_ID,
}),
createInitializeMintInstruction(
tokenAKeypair.publicKey,
decimalsA,
ctx.wallet.publicKey,
null,
TOKEN_PROGRAM_ID,
),
SystemProgram.createAccount({
fromPubkey: ctx.wallet.publicKey,
newAccountPubkey: tokenBKeypair.publicKey,
space: 82,
lamports:
await ctx.provider.connection.getMinimumBalanceForRentExemption(82),
programId: TOKEN_PROGRAM_ID,
}),
createInitializeMintInstruction(
tokenBKeypair.publicKey,
decimalsB,
ctx.wallet.publicKey,
null,
TOKEN_PROGRAM_ID,
),
],
cleanupInstructions: [],
signers: [tokenAKeypair, tokenBKeypair],
}).buildAndExecute();

const initSqrtPrice = PriceMath.tickIndexToSqrtPriceX64(123456);
const tokenVaultAKeypair = Keypair.generate();
const tokenVaultBKeypair = Keypair.generate();
const whirlpoolPda = PDAUtil.getWhirlpool(
ctx.program.programId,
whirlpoolsConfig,
tokenAKeypair.publicKey,
tokenBKeypair.publicKey,
tickSpacing,
);

// event verification
let eventVerified = false;
let detectedSignature = null;
const listener = ctx.program.addEventListener(
"PoolInitialized",
(event, _slot, signature) => {
detectedSignature = signature;
// verify
assert.equal(event.decimalsA, decimalsA);
assert.equal(event.decimalsB, decimalsB);
assert.equal(event.tickSpacing, tickSpacing);
assert.ok(event.initialSqrtPrice.eq(initSqrtPrice));
assert.ok(event.tokenMintA.equals(tokenAKeypair.publicKey));
assert.ok(event.tokenMintB.equals(tokenBKeypair.publicKey));
assert.ok(event.tokenProgramA.equals(TOKEN_PROGRAM_ID));
assert.ok(event.tokenProgramB.equals(TOKEN_PROGRAM_ID));
assert.ok(event.whirlpool.equals(whirlpoolPda.publicKey));
assert.ok(event.whirlpoolsConfig.equals(whirlpoolsConfig));
eventVerified = true;
},
);

const signature = await toTx(
ctx,
WhirlpoolIx.initializePoolIx(ctx.program, {
feeTierKey: poolInitInfo.feeTierKey,
funder: ctx.wallet.publicKey,
initSqrtPrice,
tickSpacing,
whirlpoolsConfig,
tokenMintA: tokenAKeypair.publicKey,
tokenMintB: tokenBKeypair.publicKey,
tokenVaultAKeypair,
tokenVaultBKeypair,
whirlpoolPda,
}),
)
.addSigner(tokenVaultAKeypair)
.addSigner(tokenVaultBKeypair)
.buildAndExecute();

await sleep(2000);
assert.equal(signature, detectedSignature);
assert.ok(eventVerified);

ctx.program.removeEventListener(listener);
});
});
Loading
Loading