Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Reference

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.

addLiquidity

Accounts

AccountSignerWritableSupplied
usercaller
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)

Arguments

ArgumentType
amountAu64
amountBu64
minLpTokensu64

A first deposit mints LP and locks minimum liquidity

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

Authority

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;

Ownership

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;

Accounts

AccountSignerWritableOwner
Alicesystem
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

Integration

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,
});

initialize

Accounts

AccountSignerWritableSupplied
initializercaller
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)

Arguments

ArgumentType
seedu64
feeBpsu16
authorityoption

A pool is initialized

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

Authority

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;

Ownership

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;

Accounts

AccountSignerWritableOwner
Adminsystem
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

Integration

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 */,
});

removeLiquidity

Accounts

AccountSignerWritableSupplied
usercaller
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)

Arguments

ArgumentType
lpBurnu64
minAu64
minBu64

setLocked

Accounts

AccountSignerWritableSupplied
authority·caller
config·caller

Arguments

ArgumentType
lockedbool

The atomic sandwich: a locked pool is no boundary against the authority

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

Authority

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;

Ownership

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;

Accounts

AccountSignerWritableOwner
Mallorysystem
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

Integration

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,
});

swap

Accounts

AccountSignerWritableSupplied
usercaller
mintX··caller
mintY··caller
config··caller
vaultX·default (PDA)
vaultY·default (PDA)
userX·default (PDA)
userY·default (PDA)
tokenProgram··default (fixed key)

Arguments

ArgumentType
kindswapKind
aToBbool

updateAuthority

Accounts

AccountSignerWritableSupplied
authority·caller
config·caller

Arguments

ArgumentType
newAuthorityoption

updateFee

Accounts

AccountSignerWritableSupplied
authority·caller
config·caller

Arguments

ArgumentType
newFeeBpsu16

Errors

CodeNameMessage
6000zeroAmountInput amount is zero
6001zeroReserveA reserve is zero
6002zeroDivDivision by zero
6003invalidFeeFee bps is out of range (must be < FEE_DENOMINATOR)
6004overflowArithmetic overflow
6005underflowArithmetic underflow
6006insufficientOutputComputed output rounded to zero
6007insufficientLiquidityPool cannot satisfy the request
6008poolLockedPool is locked
6009slippageExceededSlippage tolerance exceeded
6010unauthorizedSigner does not match Config.authority
6011authorityRenouncedAuthority has been renounced; pool is immutable