Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

feature: Added batch instruction #7

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

Conversation

deanmlittle
Copy link

The vast majority of CUs being burnt on the Token Program now that it has been cleaned up are on CPI. In the case of an AMM, one of the most common smart contracts on Solana, at a bare minimum, we typically need to perform:

  1. User invokes Swap program
  2. Swap program CPIs into Token program, transfers Token A from User -> Vault
  3. Swap program CPIs into Token program, transfers Token B from Vault - > User

These CPIs each incur a 1000 CU fee. By batching, we could reduce the bare minimum cost by at least 1000 CUs.

How does it work?

We introduce a new instruction with discriminator 255 called "Batch".

Batch takes in:
u8 - Counter of how many IXs to batch

For each IX in the counter:
u8 - Discriminator of IX
u8 * N - indices in the &[AccountInfo] of the Batch instruction where each of the accounts used can be mapped, similar to how instructions in transaction messages are encoded on Solana.
&[u8] - Instruction data

This function will execute the processors of each instruction recursively until either an error occurs, or it reaches the end of the batch counter and returns successfully. By using a single CPI entry to perform multiple commonly executed instructions, we can dramatically optimize the average CU usage of the Token Program even further.

@deanmlittle
Copy link
Author

deanmlittle commented Jan 29, 2025

For reference, I have also added an alternative version here called fast-batch: https://github.com/deanmlittle/p-token/tree/fast-batch

This version uses about ~300 CUs less on our test vectors (from 1594 in @febo's current refactor of this implementation down to 1297) because it dedups the accounts and relies upon local indexes. It also disables the use of multisig signers and only allows the fast subset of instructions to be batched.

One downside is that it currently uses a Vec for deduplication. It would perhaps be better to use a VecArray or something. We also have not yet figured out how we would handle CPI, but it would seem for the most part to more or less do what our tests do.

@febo
Copy link
Owner

febo commented Feb 2, 2025

Added a few improvements and the CU is down to 1511 on the current test.

Additionally, completed a CPI test with 3 instructions:

  • InitializeMint
  • InitializeAccount
  • MintTo

Standard approach (3 CPIs)

Executing instruction as a sequence of CPIs:

InitializeMint {
    mint: &mint,
    rent_sysvar: &rent_sysvar,
    mint_authority: owner.key(),
    freeze_authority: None,
    decimals: 2,
}
.invoke()?;

InitializeAccount {
    account: &account,
    mint: &mint,
    owner: &owner,
    rent_sysvar: &rent_sysvar,
}
.invoke()?;

MintTo {
    mint: &mint,
    account: &account,
    mint_authority: &owner,
    amount: 10,
}
.invoke()?;

Total CU 5330 of the program (including the entrypoint).

Batch approach (1 CPI)

Executing 3 instructions in a single CPI:

let initialize_mint = InitializeMint {
    mint: &mint,
    rent_sysvar: &rent_sysvar,
    mint_authority: owner.key(),
    freeze_authority: None,
    decimals: 2,
};

let initialize_account = InitializeAccount {
    account: &account,
    mint: &mint,
    owner: &owner,
    rent_sysvar: &rent_sysvar,
};

let mint_to = MintTo {
    mint: &mint,
    account: &account,
    mint_authority: &owner,
    amount: 10,
};

unsafe {
    Batch {
        instructions: &[&initialize_mint, &initialize_account, &mint_to],
    }
    .invoke_signed_unchecked(&[]);
}

Total CU 3313 of the program (including the entrypoint).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants