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

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