Make
Kita sekarang dapat beralih ke instruksi make, yang berada di make.rs dan akan melakukan tindakan-tindakan berikut:
Menginisialisasi catatan Escrow dan menyimpan semua persyaratannya.
Membuat Vault (ATA untuk
mint_ayang dimiliki olehescrow).Memindahkan Token A milik pembuat ke vault tersebut dengan CPI ke program SPL-Token.
Akun
Akun-akun yang dibutuhkan dalam konteks ini adalah:
maker: pengguna yang menentukan persyaratan dan menyetormint_ake dalamEscrowescrow: akun yang menyimpan persyaratan pertukaran (pembuat, mint, jumlah)mint_a: token yang disetor olehmakermint_b: token yang diinginkanmakersebagai pertukaranmaker_ata_a: akun token yang terkait denganmakerdanmint_ayang digunakan untuk menyetor token ke dalamvaultvault: akun token yang terkait denganescrowdanmint_atempat token yang disetor disimpanassociated_token_program: program token terkait yang digunakan untuk membuat akun token terkaittoken_program: program token yang digunakan untuk CPI transfersystem_program: program sistem yang digunakan untuk membuatEscrow
Dan dengan semua batasan itu akan terlihat seperti ini:
#[derive(Accounts)]
#[instruction(seed: u64)]
pub struct Make<'info> {
#[account(mut)]
pub maker: Signer<'info>,
#[account(
init,
payer = maker,
space = Escrow::INIT_SPACE + Escrow::DISCRIMINATOR.len(),
seeds = [b"escrow", maker.key().as_ref(), seed.to_le_bytes().as_ref()],
bump,
)]
pub escrow: Account<'info, Escrow>,
/// Token Accounts
#[account(
mint::token_program = token_program
)]
pub mint_a: InterfaceAccount<'info, Mint>,
#[account(
mint::token_program = token_program
)]
pub mint_b: InterfaceAccount<'info, Mint>,
#[account(
mut,
associated_token::mint = mint_a,
associated_token::authority = maker,
associated_token::token_program = token_program
)]
pub maker_ata_a: InterfaceAccount<'info, TokenAccount>,
#[account(
init,
payer = maker,
associated_token::mint = mint_a,
associated_token::authority = escrow,
associated_token::token_program = token_program
)]
pub vault: InterfaceAccount<'info, TokenAccount>,
/// Programs
pub associated_token_program: Program<'info, AssociatedToken>,
pub token_program: Interface<'info, TokenInterface>,
pub system_program: Program<'info, System>,
}Catatan: Instruksi ini meneruskan satu token_program. Karena take mentransfer untuk kedua mint, kita harus memastikan kedua mint dimiliki oleh program yang sama (SPL Token atau Token-2022), atau CPI akan gagal.
Logika
Setelah menginisialisasi Akun, akhirnya kita dapat menangani logika dengan membuat fungsi pembantu yang lebih kecil sebagai implementasi dari struct akun.
Kita mulai dengan mengisi Escrow menggunakan helper set_inner(), dan kemudian kita lanjutkan dengan menyetor token melalui CPI transfer seperti ini:
impl<'info> Make<'info> {
/// # Create the Escrow
fn populate_escrow(&mut self, seed: u64, amount: u64, bump: u8) -> Result<()> {
self.escrow.set_inner(Escrow {
seed,
maker: self.maker.key(),
mint_a: self.mint_a.key(),
mint_b: self.mint_b.key(),
receive: amount,
bump,
});
Ok(())
}
/// # Deposit the tokens
fn deposit_tokens(&self, amount: u64) -> Result<()> {
transfer_checked(
CpiContext::new(
self.token_program.to_account_info(),
TransferChecked {
from: self.maker_ata_a.to_account_info(),
mint: self.mint_a.to_account_info(),
to: self.vault.to_account_info(),
authority: self.maker.to_account_info(),
},
),
amount,
self.mint_a.decimals,
)?;
Ok(())
}
}Kita dapat melihat bahwa Anchor membantu kita dalam beberapa cara:
set_inner(): menjamin setiap field terisi.transfer_checked: membungkus Token CPI sama seperti System helper yang kita gunakan sebelumnya.
Dan sekarang kita dapat melanjutkan dengan membuat fungsi handler di mana kita melakukan beberapa pemeriksaan sebelum menggunakan helper, seperti ini:
pub fn handler(ctx: Context<Make>, seed: u64, receive: u64, amount: u64) -> Result<()> {
// Validate the amount
require_gt!(receive, 0, EscrowError::InvalidAmount);
require_gt!(amount, 0, EscrowError::InvalidAmount);
// Save the Escrow Data
ctx.accounts.populate_escrow(seed, receive, ctx.bumps.escrow)?;
// Deposit Tokens
ctx.accounts.deposit_tokens(amount)?;
Ok(())
}Di sini kita menambahkan dua pemeriksaan validasi; satu pada argumen amount dan satu lagi pada argumen receive untuk memastikan kita tidak memasukkan nilai nol untuk keduanya.
Peringatan
Ekstensi tertentu dari SPL Token-2022 misalnya, transfer hooks, confidential transfers, default account states dapat memperkenalkan kerentanan seperti memblokir transfer, mengunci dana, dan menyebabkan rug pull dalam logika escrow, vault, atau CPI.
Pastikan
mint_adanmint_bdimiliki oleh program token yang sama untuk mencegah kegagalan CPI.Gunakan token yang telah diaudit dengan baik (misalnya, USDC, wSOL) dari program SPL Token standar.
Hindari mint Token-2022 yang belum diverifikasi atau kompleks.