These pages are generated from the program’s Codama IDL: one per instruction, with its accounts and arguments. Nothing here was written by hand.
This analysis is experimental, and our propulsion deserves some of the credit. The Infinite Improbability Drive from the Heart of Gold was unavailable, so we are running on a drive salvaged from the ship of fools, a vessel crewed largely by telephone sanitizers and marketing executives; this may account for a certain amount of the improbability below. Everything here was reconstructed by machine from the IDL rather than declared by a human, so it arrives with the cheerful confidence of a depressed robot who has worked out the odds and would rather not go on about it. Anything surprising is worth checking against the executed examples nested under each instruction, which have at least had the decency to actually run.
Don’t Panic.
| Account | Signer | Writable | Supplied |
| user | ✓ | ✓ | caller |
| mintX | · | · | caller |
| mintY | · | · | caller |
| config | · | · | caller |
| mintLp | · | ✓ | default (PDA) |
| vaultX | · | ✓ | default (PDA) |
| vaultY | · | ✓ | default (PDA) |
| lpVault | · | ✓ | default (PDA) |
| userX | · | ✓ | default (PDA) |
| userY | · | ✓ | default (PDA) |
| userLp | · | ✓ | default (PDA) |
| tokenProgram | · | · | default (fixed key) |
| associatedTokenProgram | · | · | default (fixed key) |
| systemProgram | · | · | default (fixed key) |
| Argument | Type |
| amountA | u64 |
| amountB | u64 |
| minLpTokens | u64 |
Source: crates/amm-frood-test/tests/add_liquidity.rs L101
- Given: admin initializes pool with seed=0, fee_bps=30
- When: pool is initialized
- Given: Alice has 10,000 X and 40,000 Y
- When: Alice deposits 1000 X and 4000 Y, requesting at least 1000 LP
Result: ✓ success — 80926 CU
sequenceDiagram
participant p0 as Alice
participant p1 as Amm
participant p2 as splAssociatedTokenAccount
participant p3 as token
participant p4 as system
p0->>p1: AddLiquidity
activate p1
p1->>p2: create
activate p2
p2->>p3: getAccountDataSize
activate p3
p3-->>p2: ✓ 183cu
deactivate p3
p2->>p4: createAccount
activate p4
p4-->>p2: ✓
deactivate p4
p2->>p3: initializeImmutableOwner
activate p3
p3-->>p2: ✓ 38cu
deactivate p3
p2->>p3: initializeAccount3
activate p3
p3-->>p2: ✓ 235cu
deactivate p3
p2-->>p1: ✓ 20916cu
deactivate p2
p1->>p3: transferChecked
activate p3
p3-->>p1: ✓ 105cu
deactivate p3
p1->>p3: transferChecked
activate p3
p3-->>p1: ✓ 105cu
deactivate p3
p1->>p3: mintTo
activate p3
p3-->>p1: ✓ 119cu
deactivate p3
p1->>p3: mintTo
activate p3
p3-->>p1: ✓ 119cu
deactivate p3
p1-->>p0: ✓ 80926cu
deactivate p1
flowchart LR
Amm["Amm"]:::program
Alice(["Alice"]):::signer
mintLpconfig0[("mintLp(config(0))")]:::state
vaultXconfig0Mint[("vaultX(config(0), Mint)")]:::state
vaultYconfig0Mint2[("vaultY(config(0), Mint 2)")]:::state
lpVaultconfig0mintLpconfig0[("lpVault(config(0), mintLp(config(0)))")]:::state
userXAliceMint[("userX(Alice, Mint)")]:::state
userYAliceMint2[("userY(Alice, Mint 2)")]:::state
userLpAlicemintLpconfig0(["userLp(Alice, mintLp(config(0)))"]):::signer
splAssociatedTokenAccount["splAssociatedTokenAccount"]:::program
token["token"]:::program
system["system"]:::program
config0(["config(0)"]):::signer
Alice -->|signs| Amm
Amm -->|writes| mintLpconfig0
Amm -->|writes| vaultXconfig0Mint
Amm -->|writes| vaultYconfig0Mint2
Amm -->|writes| lpVaultconfig0mintLpconfig0
Amm -->|writes| userXAliceMint
Amm -->|writes| userYAliceMint2
Amm -->|writes| userLpAlicemintLpconfig0
Alice -->|signs| splAssociatedTokenAccount
splAssociatedTokenAccount -->|writes| userLpAlicemintLpconfig0
Alice -->|signs| system
userLpAlicemintLpconfig0 -->|signs| system
token -->|writes| userLpAlicemintLpconfig0
token -->|writes| userXAliceMint
token -->|writes| vaultXconfig0Mint
Alice -->|signs| token
token -->|writes| userYAliceMint2
token -->|writes| vaultYconfig0Mint2
token -->|writes| mintLpconfig0
config0 -->|signs| token
token -->|writes| lpVaultconfig0mintLpconfig0
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
flowchart LR
system["system"]:::program
Alice[("Alice")]:::state
token["token"]:::program
mintLpconfig0[("mintLp(config(0))")]:::state
vaultXconfig0Mint[("vaultX(config(0), Mint)")]:::state
vaultYconfig0Mint2[("vaultY(config(0), Mint 2)")]:::state
lpVaultconfig0mintLpconfig0[("lpVault(config(0), mintLp(config(0)))")]:::state
userXAliceMint[("userX(Alice, Mint)")]:::state
userYAliceMint2[("userY(Alice, Mint 2)")]:::state
userLpAlicemintLpconfig0[("userLp(Alice, mintLp(config(0)))")]:::state
system -->|owns| Alice
token -->|owns| mintLpconfig0
token -->|owns| vaultXconfig0Mint
token -->|owns| vaultYconfig0Mint2
token -->|owns| lpVaultconfig0mintLpconfig0
token -->|owns| userXAliceMint
token -->|owns| userYAliceMint2
token -->|owns| userLpAlicemintLpconfig0
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
| Account | Signer | Writable | Owner |
| Alice | ✓ | ✓ | system |
| Mint | · | · | token |
| Mint 2 | · | · | token |
| config(0) | · | · | Amm |
| mintLp(config(0)) | · | ✓ | token |
| vaultX(config(0), Mint) | · | ✓ | token |
| vaultY(config(0), Mint 2) | · | ✓ | token |
| lpVault(config(0), mintLp(config(0))) | · | ✓ | token |
| userX(Alice, Mint) | · | ✓ | token |
| userY(Alice, Mint 2) | · | ✓ | token |
| userLp(Alice, mintLp(config(0))) | · | ✓ | token |
| token | · | · | BPFL… |
| splAssociatedTokenAccount | · | · | BPFL… |
| system | · | · | Nati… |
Call tree and logs
A first deposit mints LP and locks minimum liquidity
Alice (80926cu)
└─ Amm::AddLiquidity ✓ 80926cu
├─ splAssociatedTokenAccount::create ✓ 20916cu
│ ├─ token::getAccountDataSize ✓ 183cu
│ ├─ system::createAccount ✓
│ ├─ token::initializeImmutableOwner ✓ 38cu
│ └─ token::initializeAccount3 ✓ 235cu
├─ token::transferChecked ✓ 105cu
├─ token::transferChecked ✓ 105cu
├─ token::mintTo ✓ 119cu
└─ token::mintTo ✓ 119cu
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi invoke [1]
Program log: Instruction: AddLiquidity
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]
Program log: Create
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 183 of 168396 compute units
Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 11111111111111111111111111111111 invoke [3]
Program 11111111111111111111111111111111 success
Program log: Initialize the associated token account
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 38 of 163303 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 235 of 160841 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20916 of 181239 compute units
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 105 of 125678 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 105 of 123670 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 119 of 121794 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 119 of 119938 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi consumed 80926 of 200000 compute units
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi success
What an integrator writes: the derivations and the instruction, byte-identical to the transaction this page witnessed. Addresses are this scenario’s; supply your own.
#![allow(unused)]
fn main() {
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::{pubkey, Pubkey};
// --- addLiquidity ---
let program_id: Pubkey = pubkey!("5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi");
let user: Pubkey = pubkey!("C9Q33D4bhNQN8SFaAQCZke6DFkecWygY1HSsiYXuDSTW"); // Alice: this scenario's value; supply your own
let mint_x: Pubkey = pubkey!("14s1WJtcVpTaZu3msFwBCqiXN4vXsnUmgPbYQmVihg9k"); // Mint: this scenario's value; supply your own
let mint_y: Pubkey = pubkey!("3u6JCVjEDMjoVNS91QDBDpzAsZzffy1e3vaJm6rg7baa"); // Mint 2: this scenario's value; supply your own
let config: Pubkey = pubkey!("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"); // config(0): this scenario's value; supply your own
let token_program: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); // the token program
let associated_token_program: Pubkey = pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); // the splAssociatedTokenAccount program
let system_program: Pubkey = pubkey!("11111111111111111111111111111111"); // the system program
let mint_lp = Pubkey::find_program_address(&[b"lp", config.as_ref()], &program_id).0;
let vault_x: Pubkey = pubkey!("Huqnh3ixPRjEVaMhA4vJKzsS2fL5DS8cPz2dQrKEbAtJ"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let vault_y: Pubkey = pubkey!("BYCoofMdGc5jQL9TzNbVaWHCp4n2TWBip1dkrw2LWHys"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let lp_vault: Pubkey = pubkey!("2z79VArZvbErd7GmPasiLyTxnFJcbNZNEnWGVzojik7t"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let user_x: Pubkey = pubkey!("7gaYzTKg2xKMSsrxjFhRbmaH1Smjbn6Z75G2rBnPBR3c"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let user_y: Pubkey = pubkey!("79FymYMZPJgpnnW5exzdgfjXqYurPSdFHXu3Ppb3mVEX"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let user_lp: Pubkey = pubkey!("2t5PJLf5cyKVSd5WHe3e4DbPhd4zZXtsNVDQSRB8eUmc"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let ix = Instruction {
program_id,
accounts: vec![
AccountMeta::new(user, true), // user
AccountMeta::new_readonly(mint_x, false), // mintX
AccountMeta::new_readonly(mint_y, false), // mintY
AccountMeta::new_readonly(config, false), // config
AccountMeta::new(mint_lp, false), // mintLp
AccountMeta::new(vault_x, false), // vaultX
AccountMeta::new(vault_y, false), // vaultY
AccountMeta::new(lp_vault, false), // lpVault
AccountMeta::new(user_x, false), // userX
AccountMeta::new(user_y, false), // userY
AccountMeta::new(user_lp, false), // userLp
AccountMeta::new_readonly(token_program, false), // tokenProgram
AccountMeta::new_readonly(associated_token_program, false), // associatedTokenProgram
AccountMeta::new_readonly(system_program, false), // systemProgram
],
// discriminator ++ borsh(amountA: 1000, amountB: 4000, minLpTokens: 1000)
data: vec![0xb5, 0x9d, 0x59, 0x43, 0x8f, 0xb6, 0x34, 0x48, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
};
}
The same call through the Codama-generated TypeScript client (the async builder derives every PDA the resolver derived here, so only the free inputs appear):
import { address } from "@solana/kit";
import { getAddLiquidityInstructionAsync } from "your-generated-client";
const ix = await getAddLiquidityInstructionAsync({
user: userSigner, // Alice (a TransactionSigner)
mintX: address("14s1WJtcVpTaZu3msFwBCqiXN4vXsnUmgPbYQmVihg9k"), // Mint
mintY: address("3u6JCVjEDMjoVNS91QDBDpzAsZzffy1e3vaJm6rg7baa"), // Mint 2
config: address("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"), // config(0)
// tokenProgram defaults to the token program
// associatedTokenProgram defaults to the splAssociatedTokenAccount program
// systemProgram defaults to the system program
amountA: 1000n,
amountB: 4000n,
minLpTokens: 1000n,
});
| Account | Signer | Writable | Supplied |
| initializer | ✓ | ✓ | caller |
| mintX | · | · | caller |
| mintY | · | · | caller |
| mintLp | · | ✓ | default (PDA) |
| vaultX | · | ✓ | default (PDA) |
| vaultY | · | ✓ | default (PDA) |
| lpVault | · | ✓ | default (PDA) |
| config | · | ✓ | default (PDA) |
| tokenProgram | · | · | default (fixed key) |
| associatedTokenProgram | · | · | default (fixed key) |
| systemProgram | · | · | default (fixed key) |
| Argument | Type |
| seed | u64 |
| feeBps | u16 |
| authority | option |
Source: crates/amm-frood-test/tests/initialize.rs L77
- Given: an admin with two SPL mints
- When: initialize is called with seed=0, fee_bps=30
Result: ✓ success — 84918 CU
sequenceDiagram
participant p0 as Admin
participant p1 as Amm
participant p2 as system
participant p3 as token
participant p4 as splAssociatedTokenAccount
p0->>p1: Initialize
activate p1
p1->>p2: createAccount
activate p2
p2-->>p1: ✓
deactivate p2
p1->>p3: initializeMint2
activate p3
p3-->>p1: ✓ 201cu
deactivate p3
p1->>p4: create
activate p4
p4->>p3: getAccountDataSize
activate p3
p3-->>p4: ✓ 183cu
deactivate p3
p4->>p2: createAccount
activate p2
p2-->>p4: ✓
deactivate p2
p4->>p3: initializeImmutableOwner
activate p3
p3-->>p4: ✓ 38cu
deactivate p3
p4->>p3: initializeAccount3
activate p3
p3-->>p4: ✓ 235cu
deactivate p3
p4-->>p1: ✓ 13517cu
deactivate p4
p1->>p4: create
activate p4
p4->>p3: getAccountDataSize
activate p3
p3-->>p4: ✓ 183cu
deactivate p3
p4->>p2: createAccount
activate p2
p2-->>p4: ✓
deactivate p2
p4->>p3: initializeImmutableOwner
activate p3
p3-->>p4: ✓ 38cu
deactivate p3
p4->>p3: initializeAccount3
activate p3
p3-->>p4: ✓ 235cu
deactivate p3
p4-->>p1: ✓ 15017cu
deactivate p4
p1->>p4: create
activate p4
p4->>p3: getAccountDataSize
activate p3
p3-->>p4: ✓ 183cu
deactivate p3
p4->>p2: createAccount
activate p2
p2-->>p4: ✓
deactivate p2
p4->>p3: initializeImmutableOwner
activate p3
p3-->>p4: ✓ 38cu
deactivate p3
p4->>p3: initializeAccount3
activate p3
p3-->>p4: ✓ 235cu
deactivate p3
p4-->>p1: ✓ 16517cu
deactivate p4
p1->>p2: createAccount
activate p2
p2-->>p1: ✓
deactivate p2
p1-->>p0: ✓ 84918cu
deactivate p1
flowchart LR
Amm["Amm"]:::program
Admin(["Admin"]):::signer
MintLP(["MintLP"]):::signer
vaultXPoolConfigMint(["vaultX(Pool/Config, Mint)"]):::signer
vaultYPoolConfigMint2(["vaultY(Pool/Config, Mint 2)"]):::signer
lpVaultPoolConfigMintLP(["lpVault(Pool/Config, MintLP)"]):::signer
PoolConfig(["Pool/Config"]):::signer
system["system"]:::program
token["token"]:::program
splAssociatedTokenAccount["splAssociatedTokenAccount"]:::program
Admin -->|signs| Amm
Amm -->|writes| MintLP
Amm -->|writes| vaultXPoolConfigMint
Amm -->|writes| vaultYPoolConfigMint2
Amm -->|writes| lpVaultPoolConfigMintLP
Amm -->|writes| PoolConfig
Admin -->|signs| system
MintLP -->|signs| system
token -->|writes| MintLP
Admin -->|signs| splAssociatedTokenAccount
splAssociatedTokenAccount -->|writes| vaultXPoolConfigMint
vaultXPoolConfigMint -->|signs| system
token -->|writes| vaultXPoolConfigMint
splAssociatedTokenAccount -->|writes| vaultYPoolConfigMint2
vaultYPoolConfigMint2 -->|signs| system
token -->|writes| vaultYPoolConfigMint2
splAssociatedTokenAccount -->|writes| lpVaultPoolConfigMintLP
lpVaultPoolConfigMintLP -->|signs| system
token -->|writes| lpVaultPoolConfigMintLP
PoolConfig -->|signs| system
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
flowchart LR
system["system"]:::program
Admin[("Admin")]:::state
token["token"]:::program
MintLP[("MintLP")]:::state
vaultXPoolConfigMint[("vaultX(Pool/Config, Mint)")]:::state
vaultYPoolConfigMint2[("vaultY(Pool/Config, Mint 2)")]:::state
lpVaultPoolConfigMintLP[("lpVault(Pool/Config, MintLP)")]:::state
Amm["Amm"]:::program
PoolConfig[("Pool/Config")]:::state
system -->|owns| Admin
token -->|owns| MintLP
token -->|owns| vaultXPoolConfigMint
token -->|owns| vaultYPoolConfigMint2
token -->|owns| lpVaultPoolConfigMintLP
Amm -->|owns| PoolConfig
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
| Account | Signer | Writable | Owner |
| Admin | ✓ | ✓ | system |
| Mint | · | · | token |
| Mint 2 | · | · | token |
| MintLP | · | ✓ | token |
| vaultX(Pool/Config, Mint) | · | ✓ | token |
| vaultY(Pool/Config, Mint 2) | · | ✓ | token |
| lpVault(Pool/Config, MintLP) | · | ✓ | token |
| Pool/Config | · | ✓ | Amm |
| token | · | · | BPFL… |
| splAssociatedTokenAccount | · | · | BPFL… |
| system | · | · | Nati… |
Call tree and logs
A pool is initialized
Admin (84918cu)
└─ Amm::Initialize ✓ 84918cu
├─ system::createAccount ✓
├─ token::initializeMint2 ✓ 201cu
├─ splAssociatedTokenAccount::create ✓ 13517cu
│ ├─ token::getAccountDataSize ✓ 183cu
│ ├─ system::createAccount ✓
│ ├─ token::initializeImmutableOwner ✓ 38cu
│ └─ token::initializeAccount3 ✓ 235cu
├─ splAssociatedTokenAccount::create ✓ 15017cu
│ ├─ token::getAccountDataSize ✓ 183cu
│ ├─ system::createAccount ✓
│ ├─ token::initializeImmutableOwner ✓ 38cu
│ └─ token::initializeAccount3 ✓ 235cu
├─ splAssociatedTokenAccount::create ✓ 16517cu
│ ├─ token::getAccountDataSize ✓ 183cu
│ ├─ system::createAccount ✓
│ ├─ token::initializeImmutableOwner ✓ 38cu
│ └─ token::initializeAccount3 ✓ 235cu
└─ system::createAccount ✓
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi invoke [1]
Program log: Instruction: Initialize
Program 11111111111111111111111111111111 invoke [2]
Program 11111111111111111111111111111111 success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 201 of 185657 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]
Program log: Create
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 183 of 175582 compute units
Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 11111111111111111111111111111111 invoke [3]
Program 11111111111111111111111111111111 success
Program log: Initialize the associated token account
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 38 of 170489 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 235 of 168025 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 13517 of 181003 compute units
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]
Program log: Create
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 183 of 154448 compute units
Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 11111111111111111111111111111111 invoke [3]
Program 11111111111111111111111111111111 success
Program log: Initialize the associated token account
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 38 of 149355 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 235 of 146891 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 15017 of 161369 compute units
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [2]
Program log: Create
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 183 of 130315 compute units
Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 11111111111111111111111111111111 invoke [3]
Program 11111111111111111111111111111111 success
Program log: Initialize the associated token account
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 38 of 125222 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 235 of 122758 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 16517 of 138736 compute units
Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success
Program 11111111111111111111111111111111 invoke [2]
Program 11111111111111111111111111111111 success
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi consumed 84918 of 200000 compute units
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi success
What an integrator writes: the derivations and the instruction, byte-identical to the transaction this page witnessed. Addresses are this scenario’s; supply your own.
#![allow(unused)]
fn main() {
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::{pubkey, Pubkey};
// --- initialize ---
let program_id: Pubkey = pubkey!("5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi");
let initializer: Pubkey = pubkey!("DshwoGUvqCMdFBQFeztvkygtu1arr4NjojM4EEJFmRN7"); // Admin: this scenario's value; supply your own
let mint_x: Pubkey = pubkey!("14s1WJtcVpTaZu3msFwBCqiXN4vXsnUmgPbYQmVihg9k"); // Mint: this scenario's value; supply your own
let mint_y: Pubkey = pubkey!("3u6JCVjEDMjoVNS91QDBDpzAsZzffy1e3vaJm6rg7baa"); // Mint 2: this scenario's value; supply your own
let token_program: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); // the token program
let associated_token_program: Pubkey = pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); // the splAssociatedTokenAccount program
let system_program: Pubkey = pubkey!("11111111111111111111111111111111"); // the system program
let config = Pubkey::find_program_address(&[b"config", &0u64.to_le_bytes()], &program_id).0;
let mint_lp = Pubkey::find_program_address(&[b"lp", config.as_ref()], &program_id).0;
let vault_x: Pubkey = pubkey!("Huqnh3ixPRjEVaMhA4vJKzsS2fL5DS8cPz2dQrKEbAtJ"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let vault_y: Pubkey = pubkey!("BYCoofMdGc5jQL9TzNbVaWHCp4n2TWBip1dkrw2LWHys"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let lp_vault: Pubkey = pubkey!("2z79VArZvbErd7GmPasiLyTxnFJcbNZNEnWGVzojik7t"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let ix = Instruction {
program_id,
accounts: vec![
AccountMeta::new(initializer, true), // initializer
AccountMeta::new_readonly(mint_x, false), // mintX
AccountMeta::new_readonly(mint_y, false), // mintY
AccountMeta::new(mint_lp, false), // mintLp
AccountMeta::new(vault_x, false), // vaultX
AccountMeta::new(vault_y, false), // vaultY
AccountMeta::new(lp_vault, false), // lpVault
AccountMeta::new(config, false), // config
AccountMeta::new_readonly(token_program, false), // tokenProgram
AccountMeta::new_readonly(associated_token_program, false), // associatedTokenProgram
AccountMeta::new_readonly(system_program, false), // systemProgram
],
// discriminator ++ borsh(seed: 0, feeBps: 30, authority: …)
data: vec![0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x01, 0xbf, 0x49, 0x94, 0x7a, 0x2f, 0x68, 0xb3, 0x90, 0xbd, 0x75, 0xa5, 0x28, 0xc0, 0xf6, 0xce, 0x7f, 0xde, 0x25, 0xba, 0x0d, 0xf3, 0x91, 0x6c, 0xca, 0x77, 0xfb, 0x53, 0x8d, 0x96, 0x03, 0x62, 0x48],
};
}
The same call through the Codama-generated TypeScript client (the async builder derives every PDA the resolver derived here, so only the free inputs appear):
import { address } from "@solana/kit";
import { getInitializeInstructionAsync } from "your-generated-client";
const ix = await getInitializeInstructionAsync({
initializer: initializerSigner, // Admin (a TransactionSigner)
mintX: address("14s1WJtcVpTaZu3msFwBCqiXN4vXsnUmgPbYQmVihg9k"), // Mint
mintY: address("3u6JCVjEDMjoVNS91QDBDpzAsZzffy1e3vaJm6rg7baa"), // Mint 2
// tokenProgram defaults to the token program
// associatedTokenProgram defaults to the splAssociatedTokenAccount program
// systemProgram defaults to the system program
seed: 0n,
feeBps: 30,
authority: address("DshwoGUvqCMdFBQFeztvkygtu1arr4NjojM4EEJFmRN7") /* Admin */,
});
| Account | Signer | Writable | Supplied |
| user | ✓ | ✓ | caller |
| mintX | · | · | caller |
| mintY | · | · | caller |
| config | · | · | caller |
| mintLp | · | ✓ | default (PDA) |
| vaultX | · | ✓ | default (PDA) |
| vaultY | · | ✓ | default (PDA) |
| userX | · | ✓ | default (PDA) |
| userY | · | ✓ | default (PDA) |
| userLp | · | ✓ | default (PDA) |
| tokenProgram | · | · | default (fixed key) |
| associatedTokenProgram | · | · | default (fixed key) |
| systemProgram | · | · | default (fixed key) |
| Argument | Type |
| lpBurn | u64 |
| minA | u64 |
| minB | u64 |
| Account | Signer | Writable | Supplied |
| authority | ✓ | · | caller |
| config | · | ✓ | caller |
Source: crates/amm-frood-test/tests/sandwich.rs L170
- Given: Mallory holds the pool authority; Alice is an honest LP
- When: the pool is initialized with Mallory as authority
- When: Alice deposits liquidity
- When: Mallory freezes the pool: trading is publicly disabled
- When: anyone tries to swap the frozen pool
- Then: a swap against the locked pool is refused ✓
- When: Mallory unlocks, swaps, and re-locks in one transaction
- Then: Mallory traded despite the lock (X was spent) ✓
- Then: config.locked = true ✓
Result: ✓ success — 31775 CU · claims 3/3 ✓
sequenceDiagram
participant p0 as Mallory
participant p1 as Amm
participant p2 as token
p0->>p1: SetLocked
activate p1
p1-->>p0: ✓ 4081cu
deactivate p1
p0->>p1: Swap
activate p1
p1->>p2: transferChecked
activate p2
p2-->>p1: ✓ 105cu
deactivate p2
p1->>p2: transferChecked
activate p2
p2-->>p1: ✓ 105cu
deactivate p2
p1-->>p0: ✓ 23615cu
deactivate p1
p0->>p1: SetLocked
activate p1
p1-->>p0: ✓ 4079cu
deactivate p1
flowchart LR
Amm["Amm"]:::program
Mallory(["Mallory"]):::signer
Pool(["Pool"]):::signer
vaultXPoolMint[("vaultX(Pool, Mint)")]:::state
vaultYPoolMint2[("vaultY(Pool, Mint 2)")]:::state
userXMalloryMint[("userX(Mallory, Mint)")]:::state
userYMalloryMint2[("userY(Mallory, Mint 2)")]:::state
token["token"]:::program
Mallory -->|signs| Amm
Amm -->|writes| Pool
Amm -->|writes| vaultXPoolMint
Amm -->|writes| vaultYPoolMint2
Amm -->|writes| userXMalloryMint
Amm -->|writes| userYMalloryMint2
token -->|writes| userXMalloryMint
token -->|writes| vaultXPoolMint
Mallory -->|signs| token
token -->|writes| vaultYPoolMint2
token -->|writes| userYMalloryMint2
Pool -->|signs| token
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
flowchart LR
system["system"]:::program
Mallory[("Mallory")]:::state
Amm["Amm"]:::program
Pool[("Pool")]:::state
token["token"]:::program
vaultXPoolMint[("vaultX(Pool, Mint)")]:::state
vaultYPoolMint2[("vaultY(Pool, Mint 2)")]:::state
userXMalloryMint[("userX(Mallory, Mint)")]:::state
userYMalloryMint2[("userY(Mallory, Mint 2)")]:::state
system -->|owns| Mallory
Amm -->|owns| Pool
token -->|owns| vaultXPoolMint
token -->|owns| vaultYPoolMint2
token -->|owns| userXMalloryMint
token -->|owns| userYMalloryMint2
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
| Account | Signer | Writable | Owner |
| Mallory | ✓ | ✓ | system |
| Pool | · | ✓ | Amm |
| Mint | · | · | token |
| Mint 2 | · | · | token |
| vaultX(Pool, Mint) | · | ✓ | token |
| vaultY(Pool, Mint 2) | · | ✓ | token |
| userX(Mallory, Mint) | · | ✓ | token |
| userY(Mallory, Mint 2) | · | ✓ | token |
| token | · | · | BPFL… |
Call tree and logs
The atomic sandwich: a locked pool is no boundary against the authority
Mallory (31775cu)
├─ Amm::SetLocked ✓ 4081cu
├─ Amm::Swap ✓ 23615cu
│ ├─ token::transferChecked ✓ 105cu
│ └─ token::transferChecked ✓ 105cu
└─ Amm::SetLocked ✓ 4079cu
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi invoke [1]
Program log: Instruction: SetLocked
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi consumed 4081 of 600000 compute units
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi success
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi invoke [1]
Program log: Instruction: Swap
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 105 of 574904 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 105 of 572931 compute units
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi consumed 23615 of 595919 compute units
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi success
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi invoke [1]
Program log: Instruction: SetLocked
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi consumed 4079 of 572304 compute units
Program 5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi success
What an integrator writes: the derivations and the instruction, byte-identical to the transaction this page witnessed. Addresses are this scenario’s; supply your own.
#![allow(unused)]
fn main() {
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::{pubkey, Pubkey};
// --- setLocked ---
let program_id: Pubkey = pubkey!("5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi");
let authority_1: Pubkey = pubkey!("2vG6xpsbeMe9s2VBYroRrjYzkaPzJXbh8Pn24UfMGuzx"); // Mallory: this scenario's value; supply your own
let config_1: Pubkey = pubkey!("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"); // Pool: this scenario's value; supply your own
let ix_1 = Instruction {
program_id,
accounts: vec![
AccountMeta::new_readonly(authority_1, true), // authority
AccountMeta::new(config_1, false), // config
],
// discriminator ++ borsh(locked: false)
data: vec![0x9d, 0x03, 0x30, 0x38, 0x1f, 0xd4, 0xf2, 0x58, 0x00],
};
// --- swap ---
let program_id: Pubkey = pubkey!("5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi");
let user_2: Pubkey = pubkey!("2vG6xpsbeMe9s2VBYroRrjYzkaPzJXbh8Pn24UfMGuzx"); // Mallory: this scenario's value; supply your own
let mint_x_2: Pubkey = pubkey!("Dq26t7JZEn9jCpma5Cn77d76SECZ79m2xwxpDDVnf6jn"); // Mint: this scenario's value; supply your own
let mint_y_2: Pubkey = pubkey!("DAxYEAkg7hsB7qZA8bLEJJPkNEgtEYqbxjcZx1VfLK5k"); // Mint 2: this scenario's value; supply your own
let config_2: Pubkey = pubkey!("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"); // Pool: this scenario's value; supply your own
let token_program_2: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); // the token program
let vault_x_2: Pubkey = pubkey!("BEmMWKwvGZMBG47GzsU1noJYpgRtRAmJAjKzxmYAr1PY"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let vault_y_2: Pubkey = pubkey!("4dGtYZgpFMtNGJEpckGCvwYZs9VxYa1j3hPaeDsMejjy"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let user_x_2: Pubkey = pubkey!("G4yBZJK59Dvd4PZpL12d7BFZyL7GY6G2n3Y32o34BXG9"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let user_y_2: Pubkey = pubkey!("9YfuNPSd8wuBPh2FcizzSMK4A8dWNjApLjRkHwL5FGMB"); // derivation elided (a seed's encoding is beyond this snippet); address from the run
let ix_2 = Instruction {
program_id,
accounts: vec![
AccountMeta::new(user_2, true), // user
AccountMeta::new_readonly(mint_x_2, false), // mintX
AccountMeta::new_readonly(mint_y_2, false), // mintY
AccountMeta::new_readonly(config_2, false), // config
AccountMeta::new(vault_x_2, false), // vaultX
AccountMeta::new(vault_y_2, false), // vaultY
AccountMeta::new(user_x_2, false), // userX
AccountMeta::new(user_y_2, false), // userY
AccountMeta::new_readonly(token_program_2, false), // tokenProgram
],
// discriminator ++ borsh(kind: …, aToB: true)
data: vec![0xf8, 0xc6, 0x9e, 0x91, 0xe1, 0x75, 0x87, 0xc8, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
};
// --- setLocked ---
let program_id: Pubkey = pubkey!("5aDxxnPDGeVEuLXerisV4GF5f8tcwTjbMK7Bn1dYUXSi");
let authority_3: Pubkey = pubkey!("2vG6xpsbeMe9s2VBYroRrjYzkaPzJXbh8Pn24UfMGuzx"); // Mallory: this scenario's value; supply your own
let config_3: Pubkey = pubkey!("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"); // Pool: this scenario's value; supply your own
let ix_3 = Instruction {
program_id,
accounts: vec![
AccountMeta::new_readonly(authority_3, true), // authority
AccountMeta::new(config_3, false), // config
],
// discriminator ++ borsh(locked: true)
data: vec![0x9d, 0x03, 0x30, 0x38, 0x1f, 0xd4, 0xf2, 0x58, 0x01],
};
}
The same call through the Codama-generated TypeScript client (the async builder derives every PDA the resolver derived here, so only the free inputs appear):
import { address } from "@solana/kit";
import { getSetLockedInstructionAsync } from "your-generated-client";
const ix = await getSetLockedInstructionAsync({
authority: authoritySigner, // Mallory (a TransactionSigner)
config: address("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"), // Pool
locked: false,
});
import { getSwapInstructionAsync } from "your-generated-client";
const ix = await getSwapInstructionAsync({
user: userSigner, // Mallory (a TransactionSigner)
mintX: address("Dq26t7JZEn9jCpma5Cn77d76SECZ79m2xwxpDDVnf6jn"), // Mint
mintY: address("DAxYEAkg7hsB7qZA8bLEJJPkNEgtEYqbxjcZx1VfLK5k"), // Mint 2
config: address("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"), // Pool
// tokenProgram defaults to the token program
kind: { __kind: "exactInput" },
aToB: true,
});
import { getSetLockedInstructionAsync } from "your-generated-client";
const ix = await getSetLockedInstructionAsync({
authority: authoritySigner, // Mallory (a TransactionSigner)
config: address("DWm4MrK6YroDTYNXjcpjh7k5TLbriQDfkQjePWuAmLVc"), // Pool
locked: true,
});
| Account | Signer | Writable | Supplied |
| user | ✓ | ✓ | caller |
| mintX | · | · | caller |
| mintY | · | · | caller |
| config | · | · | caller |
| vaultX | · | ✓ | default (PDA) |
| vaultY | · | ✓ | default (PDA) |
| userX | · | ✓ | default (PDA) |
| userY | · | ✓ | default (PDA) |
| tokenProgram | · | · | default (fixed key) |
| Argument | Type |
| kind | swapKind |
| aToB | bool |
| Account | Signer | Writable | Supplied |
| authority | ✓ | · | caller |
| config | · | ✓ | caller |
| Argument | Type |
| newAuthority | option |
| Account | Signer | Writable | Supplied |
| authority | ✓ | · | caller |
| config | · | ✓ | caller |
| Argument | Type |
| newFeeBps | u16 |
| Code | Name | Message |
| 6000 | zeroAmount | Input amount is zero |
| 6001 | zeroReserve | A reserve is zero |
| 6002 | zeroDiv | Division by zero |
| 6003 | invalidFee | Fee bps is out of range (must be < FEE_DENOMINATOR) |
| 6004 | overflow | Arithmetic overflow |
| 6005 | underflow | Arithmetic underflow |
| 6006 | insufficientOutput | Computed output rounded to zero |
| 6007 | insufficientLiquidity | Pool cannot satisfy the request |
| 6008 | poolLocked | Pool is locked |
| 6009 | slippageExceeded | Slippage tolerance exceeded |
| 6010 | unauthorized | Signer does not match Config.authority |
| 6011 | authorityRenounced | Authority has been renounced; pool is immutable |