Penarikan
Instruksi withdraw melakukan tiga tugas utama:
Menarik token
mint_xdanmint_yberdasarkan jumlah LP yang ingin penggunaburn.Menghitung jumlah yang akan ditarik dan memeriksa bahwa jumlahnya tidak kurang dari
mint_xdanmint_yyang ditentukan oleh pengguna.Membakar jumlah
mint_lpyang tepat dari ata pengguna.
Akun yang Diperlukan
Berikut adalah akun yang diperlukan untuk konteks ini:
user: Pengguna yang menarik token ke dalam likuiditas Amm. Harus berupasigner.mint_lp: Akun Mint yang akan mewakili likuiditas pool. Harus dilewatkan sebagaimutable.vault_x: Akun token yang menyimpan semua token X yang disimpan ke dalam pool. Harus dilewatkan sebagaimutable.vault_y: Akun token yang menyimpan semua token Y yang disimpan ke dalam pool. Harus dilewatkan sebagaimutable.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 sebagaimutable.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 sebagaimutable.user_lp_ata: Akun token terkait pengguna untuk token LP. Ini adalah akun sumber di mana token LP akan dibakar. Harus dilewatkan sebagaimutable.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. Harusexecutable.
Di sini, sekali lagi, saya akan menyerahkan implementasinya kepada Anda:
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:
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> {
//..
}
}Instruction Logic
Kita mulai dengan mendeserialkan baik instruction_data maupun accounts.
Kemudian kita perlu:
Memuat akun
Configuntuk mengambil semua data di dalamnya. Kita dapat melakukannya menggunakan helperConfig::load().Memverifikasi bahwa
AmmStatevalid (jadi jika tidak sama denganAmmState::Disabled).Memeriksa derivasi
vault_xdanvault_ysebagai Associated Token Accounts.Mendeserialkan semua akun token yang terlibat dan menggunakan data di dalamnya untuk menghitung jumlah yang akan ditarik menggunakan crate
constant-product-curvedan memeriksa slippage seperti ini:
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
Anda seharusnya cukup mahir untuk melakukan ini sendiri, jadi saya akan menyerahkan implementasinya kepada Anda:
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(())
}
}