Anchor
Anchor Escrow

Anchor Escrow

75 Graduates

Take

Bây giờ chúng ta có thể chuyển đến lệnh take, nằm trong take.rs và sẽ thực hiện các hành động sau:

  • Đóng bản ghi escrow, gửi rent lamports của nó trở lại cho maker.

  • Chuyển Token A từ vault đến taker, sau đó đóng vault.

  • Chuyển số lượng Token B đã thỏa thuận từ taker đến maker.

Tài khoản

Các tài khoản cần thiết trong ngữ cảnh này là:

  • taker: người dùng chấp nhận các điều khoản của maker và đang thực hiện trao đổi

  • maker: người dùng ban đầu đặt ra các điều khoản

  • escrow: tài khoản nơi tất cả các điều khoản của việc trao đổi này tồn tại

  • mint_a: token mà maker đã gửi

  • mint_b: token mà maker muốn đổi lấy

  • vault: tài khoản token liên kết với escrowmint_a sẽ gửi token đến taker

  • taker_ata_a: tài khoản token liên kết với takermint_a sẽ nhận token từ vault

  • taker_ata_b: tài khoản token liên kết với takermint_b sẽ gửi token đến maker

  • maker_ata_b: tài khoản token liên kết với makermint_b sẽ nhận token từ taker

  • associated_token_program: chương trình associated token được sử dụng để tạo các tài khoản associated token

  • token_program: chương trình token được sử dụng để CPI việc chuyển

  • system_program: chương trình hệ thống được sử dụng để tạo Escrow

Và với tất cả các ràng buộc, nó sẽ trông như thế này:

rust
#[derive(Accounts)]
pub struct Take<'info> {
  #[account(mut)]
  pub taker: Signer<'info>,
  #[account(mut)]
  pub maker: SystemAccount<'info>,
  #[account(
      mut,
      close = maker,
      seeds = [b"escrow", maker.key().as_ref(), escrow.seed.to_le_bytes().as_ref()],
      bump = escrow.bump,
      has_one = maker @ EscrowError::InvalidMaker,
      has_one = mint_a @ EscrowError::InvalidMintA,
      has_one = mint_b @ EscrowError::InvalidMintB,
  )]
  pub escrow: Box<Account<'info, Escrow>>,

  /// Token Accounts
  pub mint_a: Box<InterfaceAccount<'info, Mint>>,
  pub mint_b: Box<InterfaceAccount<'info, Mint>>,
  #[account(
      mut,
      associated_token::mint = mint_a,
      associated_token::authority = escrow,
      associated_token::token_program = token_program
  )]
  pub vault: Box<InterfaceAccount<'info, TokenAccount>>,
  #[account(
      init_if_needed,
      payer = taker,
      associated_token::mint = mint_a,
      associated_token::authority = taker,
      associated_token::token_program = token_program
  )]
  pub taker_ata_a: Box<InterfaceAccount<'info, TokenAccount>>,
  #[account(
      mut,
      associated_token::mint = mint_b,
      associated_token::authority = taker,
      associated_token::token_program = token_program
  )]
  pub taker_ata_b: Box<InterfaceAccount<'info, TokenAccount>>,
  #[account(
      init_if_needed,
      payer = taker,
      associated_token::mint = mint_b,
      associated_token::authority = maker,
      associated_token::token_program = token_program
  )]
  pub maker_ata_b: Box<InterfaceAccount<'info, TokenAccount>>,

  /// Programs
  pub associated_token_program: Program<'info, AssociatedToken>,
  pub token_program: Interface<'info, TokenInterface>,
  pub system_program: Program<'info, System>,
}

Logic

Trong logic, chúng ta bắt đầu bằng cách chuyển token từ taker_ata_b đến maker_ata_b; sau đó chúng ta chuyển sang chuyển token từ vault đến taker_ata_a trước khi đóng vault hiện đã trống như thế này:

rust
impl<'info> Take<'info> {
    fn transfer_to_maker(&mut self) -> Result<()> {
        transfer_checked(
            CpiContext::new(
                self.token_program.to_account_info(),
                TransferChecked {
                    from: self.taker_ata_b.to_account_info(),
                    to: self.maker_ata_b.to_account_info(),
                    mint: self.mint_b.to_account_info(),
                    authority: self.taker.to_account_info(),
                },
            ),
            self.escrow.receive,
            self.mint_b.decimals,
        )?;

        Ok(())
    }

    fn withdraw_and_close_vault(&mut self) -> Result<()> {
        // Create the signer seeds for the Vault
        let signer_seeds: [&[&[u8]]; 1] = [&[
            b"escrow",
            self.maker.to_account_info().key.as_ref(),
            &self.escrow.seed.to_le_bytes()[..],
            &[self.escrow.bump],
        ]];

        // Transfer Token A (Vault -> Taker)
        transfer_checked(
            CpiContext::new_with_signer(
                self.token_program.to_account_info(),
                TransferChecked {
                    from: self.vault.to_account_info(),
                    to: self.taker_ata_a.to_account_info(),
                    mint: self.mint_a.to_account_info(),
                    authority: self.escrow.to_account_info(),
                },
                &signer_seeds,
            ),
            self.vault.amount,
            self.mint_a.decimals,
        )?;

        // Close the Vault
        close_account(CpiContext::new_with_signer(
            self.token_program.to_account_info(),
            CloseAccount {
                account: self.vault.to_account_info(),
                authority: self.escrow.to_account_info(),
                destination: self.maker.to_account_info(),
            },
            &signer_seeds,
        ))?;

        Ok(())
    }
}

Bây giờ chúng ta tạo hàm handler và lần này may mắn là chúng ta không cần thực hiện thêm kiểm tra nào nên nó sẽ trông như thế này:

rust
pub fn handler(ctx: Context<Take>) -> Result<()> {
    // Transfer Token B to Maker
    ctx.accounts.transfer_to_maker()?;

    // Withdraw and close the Vault
    ctx.accounts.withdraw_and_close_vault()?;

    Ok(())
}
Next PageRefund
HOẶC BỎ QUA ĐỂ LÀM THỬ THÁCH
Sẵn sàng làm thử thách?
Nội dung
Xem mã nguồn
Blueshift © 2025Commit: e573eab