Rust
AMM Pinocchio

AMM Pinocchio

13 Graduates

Swap

Instruksi swap melakukan dua tugas utama:

  • Menghitung jumlah mint_x yang akan kita terima dengan mengirimkan sejumlah mint_y ke dalam amm (dan sebaliknya) termasuk biaya.

  • Mentransfer token from ke vault dan token to ke akun token pengguna

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

Required Accounts

Berikut adalah akun-akun yang diperlukan untuk konteks ini:

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

  • user_x_ata: Akun token terkait pengguna untuk token X. Ini adalah akun yang akan menerima atau mengirim token X ke dalam pool. Harus dilewatkan sebagai mutable.

  • user_y_ata: Akun token terkait pengguna untuk token Y. Ini adalah akun yang akan menerima atau mengirim token Y ke dalam 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.

  • 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 berupa executable.

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

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

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

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

Instruction Data

Berikut adalah data instruksi yang perlu kita masukkan:

  • is_x: Jika swap ini dilakukan dari token X ke token Y atau sebaliknya; diperlukan untuk menyelaraskan akun dengan benar. Harus berupa [u8]

  • amount: Jumlah token yang pengguna bersedia kirim sebagai pertukaran untuk token lain pada pasangan tersebut. Harus berupa [u64]

  • min: Jumlah minimum token yang pengguna bersedia terima sebagai pertukaran dari amount. 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 SwapInstructionData sama seperti inisialisasi. Jadi saya akan menyerahkan implementasinya kepada Anda:

rust
pub struct SwapInstructionData {
    pub is_x: bool,
    pub amount: u64,
    pub min: u64,
    pub expiration: i64,
}

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

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

Pastikan bahwa jumlah apapun, seperti amount dan min lebih besar dari nol dan bahwa pesanan 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 sama dengan AmmState::Initialized).

  • Memeriksa derivasi dari 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 diswap menggunakan crate constant-product-curve dan memeriksa slippage seperti ini:

rust
// Deserialize the token accounts
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)? };

// Swap Calculations
let mut curve = ConstantProduct::init(
    vault_x.amount(),
    vault_y.amount(),
    vault_x.amount(),
    config.fee(),
    None,
)
.map_err(|_| ProgramError::Custom(1))?;

let p = match self.instruction_data.is_x {
    true => LiquidityPair::X,
    false => LiquidityPair::Y,
};

let swap_result = curve
    .swap(p, self.instruction_data.amount, self.instruction_data.min)
    .map_err(|_| ProgramError::Custom(1))?;

// Check for correct values
if swap_result.deposit == 0 || swap_result.withdraw == 0 {
    return Err(ProgramError::InvalidArgument);
}
  • Buat logika transfer dengan memeriksa nilai is_x dan transfer jumlah from ke vault dan jumlah to ke akun token pengguna seperti ini:

rust
if self.instruction_data.is_x {
    Transfer {
        //...
    }
    .invoke()?;

    Transfer {
        //...
    }
    .invoke_signed(&signer_seeds)?;
} else {
    Transfer {
        //...

    }
    .invoke()?;

    Transfer {
        //...
    }
    .invoke_signed(&signer_seeds)?;
}

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

rust
pub struct Swap<'a> {
    pub accounts: SwapAccounts<'a>,
    pub instruction_data: SwapInstructionData,
}

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

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

        // Return the initialized struct
        Ok(Self {
            accounts,
            instruction_data,
        })
    }
}
impl<'a> Swap<'a> {
    pub const DISCRIMINATOR: &'a u8 = &3;

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

        Ok(())
    }
}
Next PageKesimpulan
ATAU LANGSUNG KE TANTANGAN
Siap mengambil tantangan?
Daftar Isi
Lihat Sumber
Blueshift © 2025Commit: e573eab