Deposit
Instruksi deposit melakukan tiga tugas utama:
Deposit token
mint_xdanmint_yberdasarkan jumlah LP yang ingin dimintoleh pengguna.Menghitung jumlah yang akan didepositkan dan memeriksa bahwa jumlahnya tidak lebih besar dari
max_xdanmax_yyang ditentukan oleh pengguna.Mencetak jumlah
mint_lpyang tepat ke dalam ata pengguna.
Required Accounts
Berikut adalah akun yang diperlukan untuk konteks ini:
user: Pengguna yang mendepositkan 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 didepositkan ke dalam pool. Harus dilewatkan sebagaimutable.vault_y: Akun token yang menyimpan semua token Y yang didepositkan ke dalam pool. Harus dilewatkan sebagaimutable.user_x_ata: Akun token terkait pengguna untuk token X. Ini adalah akun sumber dari mana token X pengguna akan ditransfer ke dalam pool. Harus dilewatkan sebagaimutable.user_y_ata: Akun token terkait pengguna untuk token Y. Ini adalah akun sumber dari mana token Y pengguna akan ditransfer ke dalam pool. Harus dilewatkan sebagaimutable.user_lp_ata: Akun token terkait pengguna untuk token LP. Ini adalah akun tujuan di mana token LP akan dicetak. 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 pencetakan. Harusexecutable.
Di sini, sekali lagi, saya akan menyerahkan implementasinya kepada Anda:
pub struct DepositAccounts<'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 DepositAccounts<'a> {
type Error = ProgramError;
fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
//..
}
}Instruction Data
Berikut adalah data instruksi yang perlu kita berikan:
amount: Jumlah token LP yang ingin diterima pengguna. Harus berupa[u64]max_x: Jumlah maksimum token X yang bersedia disetor oleh pengguna. Harus berupa[u64]max_y: Jumlah maksimum token Y yang bersedia disetor oleh pengguna. Harus berupa[u64]expiration: Waktu kedaluwarsa dari pesanan ini. Penting untuk memastikan bahwa transaksi harus dijalankan dalam jangka waktu tertentu. Harus berupa[i64]
Kita akan menangani implementasi untuk DepositInstructionData sama seperti inisialisasi. Jadi saya akan menyerahkan implementasinya kepada Anda:
pub struct DepositInstructionData {
pub amount: u64,
pub max_x: u64,
pub max_y: u64,
pub expiration: i64,
}
impl<'a> TryFrom<&'a [u8]> for DepositInstructionData {
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 (jika sama denganAmmState::Initialized)Memeriksa derivasi
vault_xdanvault_ysebagai Associated Token Accounts seperti ini:
// Check if the vault_x is valid
let (vault_x, _) = find_program_address(
&[
self.accounts.config.key(),
self.accounts.token_program.key(),
config.mint_x(),
],
&pinocchio_associated_token_account::ID,
);
if vault_x.ne(self.accounts.vault_x.key()) {
return Err(ProgramError::InvalidAccountData);
}Mendeserialkan semua akun token yang terlibat dan menggunakan data di dalamnya untuk menghitung jumlah yang akan disetor menggunakan crate
constant-product-curvedan memeriksa slippage seperti ini:
// Deserialize the token accounts
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)? };
// Grab the amounts to deposit
let (x, y) = match mint_lp.supply() == 0 && vault_x.amount() == 0 && vault_y.amount() == 0 {
true => (self.instruction_data.max_x, self.instruction_data.max_y),
false => {
let amounts = ConstantProduct::xy_deposit_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.max_x && y <= self.instruction_data.max_y) {
return Err(ProgramError::InvalidArgument);
}Transfer jumlah dari akun token pengguna ke vault dan mint jumlah token LP yang sesuai ke akun token pengguna
Anda seharusnya cukup mahir untuk melakukan ini sendiri, jadi saya akan menyerahkan implementasinya kepada Anda:
pub struct Deposit<'a> {
pub accounts: DepositAccounts<'a>,
pub instruction_data: DepositInstructionData,
}
impl<'a> TryFrom<(&'a [u8], &'a [AccountInfo])> for Deposit<'a> {
type Error = ProgramError;
fn try_from((data, accounts): (&'a [u8], &'a [AccountInfo])) -> Result<Self, Self::Error> {
let accounts = DepositAccounts::try_from(accounts)?;
let instruction_data = DepositInstructionData::try_from(data)?;
// Return the initialized struct
Ok(Self {
accounts,
instruction_data,
})
}
}
impl<'a> Deposit<'a> {
pub const DISCRIMINATOR: &'a u8 = &1;
pub fn process(&mut self) -> ProgramResult {
//..
Ok(())
}
}