Rust
Escrow Pinocchio

Escrow Pinocchio

47 Graduates

Take

Instruksi take menyelesaikan pertukaran:

  • Menutup catatan escrow, mengirimkan lamport sewanya kembali ke pembuat.

  • Memindahkan Token A dari vault ke pengambil, kemudian menutup vault.

  • Memindahkan jumlah Token B yang disepakati dari pengambil ke pembuat.

Required Accounts

Berikut adalah akun yang dibutuhkan oleh konteks:

  • taker: orang yang ingin mengambil penawaran. Harus menjadi penandatangan dan dapat diubah.

  • maker: pembuat escrow. Harus dapat diubah.

  • escrow: akun escrow yang kita inisialisasi. Harus dapat diubah.

  • mint_a: token yang kita setorkan ke dalam escrow

  • mint_b: token yang ingin kita terima

  • vault: akun token terkait yang dimiliki oleh escrow. Harus dapat diubah

  • taker_ata_a: akun token terkait yang dimiliki oleh pengambil untuk mint_a. Harus dapat diubah

  • taker_ata_b: akun token terkait yang dimiliki oleh pengambil untuk mint_b. Harus dapat diubah

  • maker_ata_b: akun token terkait yang dimiliki oleh pembuat untuk mint_b. Harus dapat diubah

  • system_program: program sistem. Harus dapat dieksekusi

  • token_program: program token. Harus dapat dieksekusi

Dan kita melakukan pemeriksaan berikut padanya:

rust
pub struct TakeAccounts<'a> {
  pub taker: &'a AccountInfo,
  pub maker: &'a AccountInfo,
  pub escrow: &'a AccountInfo,
  pub mint_a: &'a AccountInfo,
  pub mint_b: &'a AccountInfo,
  pub vault: &'a AccountInfo,
  pub taker_ata_a: &'a AccountInfo,
  pub taker_ata_b: &'a AccountInfo,
  pub maker_ata_b: &'a AccountInfo,
  pub system_program: &'a AccountInfo,
  pub token_program: &'a AccountInfo,
}

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

  fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
    let [taker, maker, escrow, mint_a, mint_b, vault, taker_ata_a, taker_ata_b, maker_ata_b, system_program, token_program, _] = accounts else {
      return Err(ProgramError::NotEnoughAccountKeys);
    };

    // Basic Accounts Checks
    SignerAccount::check(taker)?;
    ProgramAccount::check(escrow)?;
    MintInterface::check(mint_a)?;
    MintInterface::check(mint_b)?;
    AssociatedTokenAccount::check(taker_ata_b, taker, mint_b, token_program)?;
    AssociatedTokenAccount::check(vault, escrow, mint_a, token_program)?;

    // Return the accounts
    Ok(Self {
      taker,
      maker,
      escrow,
      mint_a,
      mint_b,
      taker_ata_a,
      taker_ata_b,
      maker_ata_b,
      vault,
      system_program,
      token_program,
    })
  }
}

Instruction Data

Semua data yang kita butuhkan untuk melakukan logika sudah ada di akun Escrow atau pada akun yang kita deserialisasi. Karena alasan ini kita tidak memerlukan instruction_data untuk instruksi ini.

Instruction Logic

Kita mulai dengan menginisialisasi akun yang diperlukan dalam implementasi TryFrom, setelah kita mendeserialisasi akun.

Untuk langkah ini, kita memastikan bahwa akun Token A milik taker dan akun Token B milik maker sudah diinisialisasi menggunakan AssociatedTokenAccount::init_if_needed karena kita tidak yakin apakah akun-akun tersebut sudah ada

rust
pub struct Take<'a> {
  pub accounts: TakeAccounts<'a>,
}

impl<'a> TryFrom<&'a [AccountInfo]> for Take<'a> {
  type Error = ProgramError;
  
  fn try_from(accounts: &'a [AccountInfo]) -> Result<Self, Self::Error> {
    let accounts = TakeAccounts::try_from(accounts)?;

    // Initialize necessary accounts
    AssociatedTokenAccount::init_if_needed(
      accounts.taker_ata_a,
      accounts.mint_a,
      accounts.taker,
      accounts.taker,
      accounts.system_program,
      accounts.token_program,
    )?;

    AssociatedTokenAccount::init_if_needed(
      accounts.maker_ata_b,
      accounts.mint_b,
      accounts.taker,
      accounts.maker,
      accounts.system_program,
      accounts.token_program,
    )?;

    Ok(Self {
      accounts,
    })
  }
}

Sekarang kita bisa fokus pada logika itu sendiri yang akan:

  • Mentransfer token dari taker_ata_b ke maker_ata_b.

  • Mentransfer token dari vault ke taker_ata_a.

  • Menutup vault yang sekarang kosong dan menarik biaya sewa dari akun tersebut.

rust
impl<'a> Take<'a> {
  pub const DISCRIMINATOR: &'a u8 = &1;
  
  pub fn process(&mut self) -> ProgramResult {
    let data = self.accounts.escrow.try_borrow_data()?;
    let escrow = Escrow::load(&data)?;

    // Check if the escrow is valid
    let escrow_key = create_program_address(&[b"escrow", self.accounts.maker.key(), &escrow.seed.to_le_bytes(), &escrow.bump], &crate::ID)?;
    if &escrow_key != self.accounts.escrow.key() {
      return Err(ProgramError::InvalidAccountOwner);
    }
    
    let seed_binding = escrow.seed.to_le_bytes();
    let bump_binding = escrow.bump;
    let escrow_seeds = [
      Seed::from(b"escrow"),
      Seed::from(self.accounts.maker.key().as_ref()),
      Seed::from(&seed_binding),
      Seed::from(&bump_binding),
    ];
    let signer = Signer::from(&escrow_seeds);
    
    let amount = TokenAccount::get_amount(self.accounts.vault);
    
    // Transfer from the Vault to the Taker
    Transfer {
      from: self.accounts.vault,
      to: self.accounts.taker_ata_a,
      authority: self.accounts.escrow,
      amount,
    }.invoke_signed(&[signer.clone()])?;

    // Close the Vault
    CloseAccount {
      account: self.accounts.vault,
      destination: self.accounts.maker,
      authority: self.accounts.escrow,
    }.invoke_signed(&[signer.clone()])?;

    // Transfer from the Taker to the Maker
    Transfer {
      from: self.accounts.taker_ata_b,
      to: self.accounts.maker_ata_b,
      authority: self.accounts.taker,
      amount: escrow.receive,
    }.invoke()?;

    // Close the Escrow
    drop(data);
    ProgramAccount::close(self.accounts.escrow, self.accounts.taker)?;

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