Rust
AMM Pinocchio

AMM Pinocchio

13 Graduates

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 melakukan 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> {
        //..
    }
}

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);
}
  • Transfer jumlah dari vault ke akun token pengguna dan bakar jumlah token LP yang sesuai dari akun token pengguna

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(())
    }
}
Next PageTukar
ATAU LANGSUNG KE TANTANGAN
Siap mengambil tantangan?
Daftar Isi
Lihat Sumber
Blueshift © 2025Commit: e573eab