Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for createPool.ts #501

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open

Conversation

calintje
Copy link
Contributor

Title
Add unit tests for createPool.ts

Details

  • Fixed the calculation of estInitializationCosts in the createConcentratedLiquidityPool function.
  • Added tests to verify the correct calculation of estInitialization costs.
  • Updated setupWhirlpool to support the V2 instruction of our program.

.send();
const nonRefundableRents: Lamports[] = await Promise.all(
stateSpaces.map(async (space) => {
const rentExemption = await rpc.getMinimumBalanceForRentExemption(BigInt(space)).send();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't do this since it would change the rpc calls it needs to make from 1 to 5 (or 6)

stateSpace += getWhirlpoolSize();
stateSpaces.push(
tokenProgramA === TOKEN_2022_PROGRAM_ADDRESS
? getTokenSize(getAccountExtensions(mintA.data))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this a separate function (should be able to check mint.owner so mint would be the only parameter)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suspect we will need the same thing in increase_liquidity too. We can put it in token.ts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then we can write a test for it 😄

setDefaultFunder(signer);
});

it("Should throw an error if token mints are not ordered", async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: they are ordered, just not ordered correctly

await assert.rejects(
createConcentratedLiquidityPoolInstructions(rpc, mintB, mintA, 64, 1),
{
name: 'AssertionError',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it exists but is there a new AssertionError("Token order needs to be flipped to match the canonical ordering (i.e. sorted on the byte repr. of the mint pubkeys)")

createConcentratedLiquidityPoolInstructions(rpc, mintB, mintA, 64, 1),
{
name: 'AssertionError',
message: 'Token order needs to be flipped to match the canonical ordering (i.e. sorted on the byte repr. of the mint pubkeys)'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we use double quotes for strings in ts (but you can run yarn format and that should format your files correctly

await createSplashPoolInstructions(rpc, mintA, mintB, price);
await sendTransaction(instructions);

const pool = await fetchWhirlpool(rpc, poolAddress);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would structure the test like this:

  • create splash pool
  • fetch maybe pool before
  • fetch signer balance before
  • assert pool does not exist
  • send tx
  • fetch maybe pool
  • fetch signer blance after
  • assert pool exists
  • assert sqrt, mintA, mintB, and tick spacing
  • assert that estInitialization cost equals difference in signer balance

That way you don't need the Should estimate initialization costs correctly test case entirely

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then create more tests with similar structure for:

  • Splash pool with TE token
  • CL pool
  • CL pool with TE token
  • etc.

import {
SPLASH_POOL_TICK_SPACING,
WHIRLPOOLS_CONFIG_ADDRESS,
} from "../../src/config";
import { tickIndexToSqrtPrice } from "@orca-so/whirlpools-core";
import { fetchMint } from "@solana-program/token";
import { a } from "vitest/dist/chunks/suite.B2jumIFP.js";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

.send();
const nonRefundableRents: Lamports[] = await Promise.all(
stateSpaces.map(async (space) => {
const rentExemption = await calculateMinimumBalance(rpc, space);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still doing the same thing where it fetches the rent 5 (or 6 times).

The way I would do it. Change the function to:

export function calculateMinimumBalance(
  rent: Rent,
  dataSize: number,
): Lamports {

Fetcht he rent sysvar at the beginning of this function and then instead of keeping track of stateSpace: Array<bigint> you can just straight up keep track of estInitializationCost: Lamports.

And then instead of doing stateSpace.push(...) you can just do estInitializationCost += calculateMinimumBalance(rent, ...)

* @param {number} dataSize - The size of the account data in bytes.
* @returns {Promise<BigInt>} The minimum balance required for rent exemption in lamports.
*/
export async function calculateMinimumBalance(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a test for this?

const price = 10;
const sqrtPrice = priceToSqrtPrice(price, 6, 6);

let signerAccount = await rpc.getAccountInfo(signer.address).send();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think nicer if we implement getBalance on the mockRpc so we don't have to duplicate this every time.

assertAccountExists(pool);

signerAccount = await rpc.getAccountInfo(signer.address).send();
const balanceAfter = signerAccount.value?.lamports ?? lamports(0n);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would group all the fetch together before starting on any assertions. poolBefore together with balanceBefore, poolAfter together with balanceAfter.

const balanceChange = balanceBefore - balanceAfter;
const txFee = 15000n; // 3 signing accounts * 5000 lamports
const minRentExempt = balanceChange - txFee;
assert.strictEqual(estInitializationCost, minRentExempt);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me see if I can make the tx fee go to 0 in bankrun so that this assertion can just become:

assert.strictEqual(estInitializationCost, balanceBefore - balanceAfter);

});

it("Should create splash pool with 1 TE token", async () => {
const mint1 = await setupMint();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would set up these mints in the beforeAll as well since that will get faster execution (init the TE mint once opposed to doing it for each TE test)

});

it("Should create splash pool with 2 TE tokens", async () => {
const mint1 = await setupMintTEFee();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the tests I would do (instead of trying to combine Transfer fee and 1/2 TE token tests):

  • 1 TE token (without extensions)
  • 2 TE tokens (without extensions)
  • 1 TE token (with transfer fee)

@@ -0,0 +1,28 @@
import { fetchSysvarRent } from "@solana/sysvars";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This should be re-exported by @solana/web3.js so you can use that as import

@calintje calintje marked this pull request as draft November 15, 2024 02:46
@calintje calintje marked this pull request as ready for review November 15, 2024 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants