Rust
AMM Pinocchio

AMM Pinocchio

Penarikan

Instruksi withdraw melakukan tiga tugas utama:

  • Menarik token mint_x dan mint_y berdasarkan jumlah LP yang ingin pengguna burn.

  • Menghitung jumlah yang akan ditarik dan memeriksa bahwa jumlahnya tidak kurang dari mint_x dan mint_y yang ditentukan oleh pengguna.

  • Membakar jumlah mint_lp yang tepat dari ata pengguna.

Seperti yang disebutkan dalam bagian instruksi initialize; kita akan menginisialisasi semua Associated Token Accounts di luar instruksi kita untuk tujuan optimasi.

Akun yang Diperlukan

Berikut adalah akun yang diperlukan untuk konteks ini:

  • user: Pengguna yang menarik token ke dalam likuiditas Amm. Harus berupa signer.

  • mint_lp: Akun Mint yang akan mewakili likuiditas pool. Harus dilewatkan sebagai mutable.

  • vault_x: Akun token yang menyimpan semua token X yang disimpan ke dalam pool. Harus dilewatkan sebagai mutable.

  • vault_y: Akun token yang menyimpan semua token Y yang disimpan ke dalam pool. Harus dilewatkan sebagai mutable.

  • user_x_ata: Akun token terkait pengguna untuk token X. Ini adalah akun tujuan ke mana token X pengguna akan ditransfer dari pool. Harus dilewatkan sebagai mutable.

  • user_y_ata: Akun token terkait pengguna untuk token Y. Ini adalah akun tujuan ke mana token Y pengguna akan ditransfer dari pool. Harus dilewatkan sebagai mutable.

  • user_lp_ata: Akun token terkait pengguna untuk token LP. Ini adalah akun sumber di mana token LP akan dibakar. Harus dilewatkan sebagai mutable.

  • config: Akun konfigurasi untuk pool AMM. Menyimpan semua parameter dan status pool yang relevan.

  • token program: Akun program SPL Token. Ini diperlukan untuk operasi token seperti transfer dan minting. Harus executable.

Di sini, sekali lagi, saya akan menyerahkan implementasinya kepada Anda:

rust
pub struct WithdrawAccounts<'a> {
    pub user: &'a AccountInfo,
    pub mint_lp: &'a AccountInfo,
    pub vault_x: &'a AccountInfo,
    pub vault_y: &'a AccountInfo,
    pub user_x_ata: &'a AccountInfo,
    pub user_y_ata: &'a AccountInfo,
    pub user_lp_ata: &'a AccountInfo,
    pub config: &'a AccountInfo,
    pub token_program: &'a AccountInfo,
}

impl<'a> TryFrom<&'a [AccountInfo]> for WithdrawAccounts<'a> {
    type Error = ProgramError;

    fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
        //..
    }
}
Expand
[4 more lines]

Instruction Data

Berikut adalah data instruksi yang perlu kita masukkan:

  • amount: Jumlah token LP yang ingin dibakar oleh pengguna. Harus berupa [u64]

  • min_x: Jumlah minimal token X yang bersedia ditarik oleh pengguna. Harus berupa [u64]

  • min_y: Jumlah minimal token Y yang bersedia ditarik oleh pengguna. Harus berupa [u64]

  • expiration: Waktu kedaluwarsa dari perintah ini. Penting untuk memastikan bahwa transaksi harus dijalankan dalam jangka waktu tertentu. Harus berupa [i64]

Kita akan menangani implementasi untuk WithdrawInstructionData sama seperti inisialisasi. Jadi saya akan menyerahkan implementasinya kepada Anda:

rust
pub struct WithdrawInstructionData {
    pub amount: u64,
    pub min_x: u64,
    pub min_y: u64,
    pub expiration: i64,
}

impl<'a> TryFrom<&'a [u8]> for WithdrawInstructionData {
    type Error = ProgramError;

    fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
        //..
    }
}

Pastikan bahwa semua jumlah, seperti amount, min_y dan min_x lebih besar dari nol dan bahwa perintah belum kedaluwarsa dengan menggunakan sysvar Clock.

Instruction Logic

Kita mulai dengan mendeserialkan baik instruction_data maupun accounts.

Kemudian kita perlu:

  • Memuat akun Config untuk mengambil semua data di dalamnya. Kita dapat melakukannya menggunakan helper Config::load().

  • Memverifikasi bahwa AmmState valid (jadi jika tidak sama dengan AmmState::Disabled).

  • Memeriksa derivasi vault_x dan vault_y sebagai Associated Token Accounts.

  • Mendeserialkan semua akun token yang terlibat dan menggunakan data di dalamnya untuk menghitung jumlah yang akan ditarik menggunakan crate constant-product-curve dan memeriksa slippage seperti ini:

rust
let mint_lp = unsafe { Mint::from_account_info_unchecked(self.accounts.mint_lp)? };
let vault_x = unsafe { TokenAccount::from_account_info_unchecked(self.accounts.vault_x)? };
let vault_y = unsafe { TokenAccount::from_account_info_unchecked(self.accounts.vault_y)? };

let (x, y) = match mint_lp.supply() == self.instruction_data.amount {
    true => (vault_x.amount(), vault_y.amount()),
    false => {
        let amounts = ConstantProduct::xy_withdraw_amounts_from_l(
            vault_x.amount(),
            vault_y.amount(),
            mint_lp.supply(),
            self.instruction_data.amount,
            6,
        )
        .map_err(|_| ProgramError::InvalidArgument)?;

        (amounts.x, amounts.y)
    }
};

// Check for slippage
if !(x >= self.instruction_data.min_x && y >= self.instruction_data.min_y) {
    return Err(ProgramError::InvalidArgument);
}
Expand
[9 more lines]
  • Transfer jumlah dari vault ke akun token pengguna dan bakar jumlah token LP yang sesuai dari akun token pengguna. Sama seperti yang kita lakukan pada instruksi Deposit, gunakan satu Batch agar kedua transfer dan satu burn dilakukan dalam satu CPI.

authority dari vault_x dan vault_y adalah akun config

Anda seharusnya cukup mahir untuk melakukan ini sendiri, jadi saya akan menyerahkan implementasinya kepada Anda:

rust
pub struct Withdraw<'a> {
    pub accounts: WithdrawAccounts<'a>,
    pub instruction_data: WithdrawInstructionData,
}

impl<'a> TryFrom<(&'a [u8], &'a [AccountInfo])> for Withdraw<'a> {
    type Error = ProgramError;

    fn try_from((data, accounts): (&'a [u8], &'a [AccountInfo])) -> Result<Self, Self::Error> {
        let accounts = WithdrawAccounts::try_from(accounts)?;
        let instruction_data = WithdrawInstructionData::try_from(data)?;

        // Return the initialized struct
        Ok(Self {
            accounts,
            instruction_data,
        })
    }
}

impl<'a> Withdraw<'a> {
    pub const DISCRIMINATOR: &'a u8 = &2;

    pub fn process(&mut self) -> ProgramResult {
        //..

        Ok(())
    }
}
Expand
[14 more lines]
Daftar Isi
Lihat Sumber
Blueshift © 2026Commit: 3c44267