Anchor
Anchor 闪电贷

Anchor 闪电贷

27 Graduates

Anchor 闪电贷

Anchor 闪电贷

Anchor 闪电贷

指令内省是一项强大的功能,它允许区块链程序检查和分析同一交易包中的其他指令。这包括尚未执行的指令,使您的程序能够“前瞻性”地根据交易后续发生的情况做出决策。

可以将其想象为交易的“X光视野”:您的程序可以透视整个交易,了解完整的操作序列,然后再决定如何进行。

指令内省最引人注目的应用是闪电贷。这是一种仅存在于单笔交易范围内的独特贷款类型。

以下是闪电贷的工作原理:

  • 借款:在交易开始时,您可以通过loan指令即时借入大量资金

  • 使用:您可以在同一笔交易中使用这笔借来的资金进行交易、套利或其他操作

  • 还款:在交易结束之前,您必须通过repay指令归还贷款并支付少量费用

关键点在于,闪电贷依赖于区块链交易的原子性。如果交易的任何部分失败(包括还款),整个交易将被回滚,就像从未发生过一样。这意味着贷款方没有任何风险:要么他们得到还款,要么贷款根本不存在。

在本次挑战中,您将创建一个简单的闪电贷程序,展示指令内省的实际应用。该程序将检查同一交易中不同指令的指令数据和账户,以确保贷款条款得到满足。

如果您是指令自省的新手,我们建议您从指令自省课程开始,以了解本程序中使用的基本概念。

安装

在开始之前,请确保您已安装 Rust 和 Anchor。如果需要安装说明,请参考官方 Anchor 文档。然后在终端中运行:

anchor init blueshift_anchor_flash_loan

添加所需的依赖项:

  • anchor-spl:提供用于处理 SPL 代币(Solana 的代币标准)的工具

cd blueshift_anchor_flash_loan
cargo add anchor-spl

现在,您已经准备好开始构建您的闪电贷程序了!

模板

让我们通过设置基本结构、账户和错误处理来构建闪电贷程序的基础,这些将被借款和还款指令共同使用。

我们将在lib.rs中实现所有内容,因为我们只有两个共享相同账户结构的指令。以下是包含所有基本组件的起始模板:

rust
use anchor_lang::prelude::*;
use anchor_spl::{
  token::{Token, TokenAccount, Mint, Transfer, transfer}, 
  associated_token::AssociatedToken
}; 
use anchor_lang::{
  Discriminator,
  solana_program::sysvar::instructions::{
      ID as INSTRUCTIONS_SYSVAR_ID,
      load_instruction_at_checked
  }
};

declare_id!("22222222222222222222222222222222222222222222");

#[program]
pub mod blueshift_anchor_flash_loan {
  use super::*;

  pub fn borrow(ctx: Context<Loan>, borrow_amount: u64) -> Result<()> {
    // borrow logic...
    
    Ok(())
  }

  pub fn repay(ctx: Context<Loan>) -> Result<()> {
    // repay logic...

    Ok(())
  }
}

#[derive(Accounts)]
pub struct Loan<'info> {
  // loan accounts...
}

#[error_code]
pub enum ProtocolError {
  // error enum..
}

注意:请记得将程序 ID 更改为22222222222222222222222222222222222222222222,因为我们在底层使用它来测试您的程序。

账户

由于borrowrepay指令使用相同的账户,我们可以创建一个单一的Loan上下文来服务于这两个功能。这使我们的代码更易于维护和理解。

我们的Loan账户结构需要以下组件:

  • borrower:请求闪电贷的用户。

  • protocol:拥有协议流动性池的程序派生地址(PDA)。

  • mint:被借用的特定代币。

  • borrower_ata:借款人的关联代币账户,用于接收借用的代币。

  • protocol_ata:协议的关联代币账户,用于提供借用的代币。

  • instructions:用于自省的指令 Sysvar 账户。

  • token_programassociated_token_programsystem_program:程序所需的其他程序。

以下是我们定义账户结构的方法:

rust
#[derive(Accounts)]
pub struct Loan<'info> {
  #[account(mut)]
  pub borrower: Signer<'info>,
  #[account(
    seeds = [b"protocol".as_ref()],
    bump,
  )]
  pub protocol: SystemAccount<'info>,

  pub mint: Account<'info, Mint>,
  #[account(
    init_if_needed,
    payer = borrower,
    associated_token::mint = mint,
    associated_token::authority = borrower,
  )]
  pub borrower_ata: Account<'info, TokenAccount>,
  #[account(
    mut,
    associated_token::mint = mint,
    associated_token::authority = protocol,
  )]
  pub protocol_ata: Account<'info, TokenAccount>,

  #[account(address = INSTRUCTIONS_SYSVAR_ID)]
  /// CHECK: InstructionsSysvar account
  instructions: UncheckedAccount<'info>,
  pub token_program: Program<'info, Token>,
  pub associated_token_program: Program<'info, AssociatedToken>,
  pub system_program: Program<'info, System>
}

如您所见,此指令所需的账户及其约束条件非常直观:

  • protocol:使用seeds = [b"protocol".as_ref()]创建一个确定性的地址,该地址拥有所有协议流动性。这确保了只有我们的程序可以控制这些资金。

  • borrower_ata:使用init_if_needed,因为借款人可能尚未为此特定代币创建关联的代币账户。如果需要,约束条件会自动创建一个。

  • protocol_ata:必须已经存在并且是可变的,因为我们将从中转移代币。associated_token::authority = protocol约束条件确保只有协议PDA可以授权转移。

  • instructions:使用address约束条件来验证我们正在访问包含交易指令数据的正确系统账户。

错误

闪电贷在多个步骤中需要精确验证,因此我们需要全面的错误处理。以下是完整的错误枚举:

rust
#[error_code]
pub enum ProtocolError {
    #[msg("Invalid instruction")]
    InvalidIx,
    #[msg("Invalid instruction index")]
    InvalidInstructionIndex,
    #[msg("Invalid amount")]
    InvalidAmount,
    #[msg("Not enough funds")]
    NotEnoughFunds,
    #[msg("Program Mismatch")]
    ProgramMismatch,
    #[msg("Invalid program")]
    InvalidProgram,
    #[msg("Invalid borrower ATA")]
    InvalidBorrowerAta,
    #[msg("Invalid protocol ATA")]
    InvalidProtocolAta,
    #[msg("Missing repay instruction")]
    MissingRepayIx,
    #[msg("Missing borrow instruction")]
    MissingBorrowIx,
    #[msg("Overflow")]
    Overflow,
}

有了这个基础,我们就可以准备实现闪电贷指令的核心逻辑了。账户结构确保了代币的正确处理,而错误系统为调试和安全验证提供了清晰的反馈。

程序还无法完全编译。您能找出原因吗?

Next Page借款
或者跳到挑战
准备接受挑战了吗?
Blueshift © 2025Commit: e573eab