Rust
Pinocchio Flash Loan

Pinocchio Flash Loan

14 Graduates

Pinocchio Flash Loan

Pinocchio 閃電貸款

Pinocchio 閃電貸款

指令內省是一個強大的功能,允許區塊鏈程式檢查和分析同一交易包內的其他指令。這包括尚未執行的指令,使您的程式能夠「預見」並根據交易稍後發生的情況作出決策。

可以將其想像成交易的 X 光視野:您的程式可以透視整個交易,了解完整的操作序列,然後再決定如何進行。

指令內省最引人注目的應用是閃電貸款。這是一種僅存在於單一交易範圍內的獨特貸款類型。

以下是閃電貸款的運作方式:

  • 借款:在交易開始時,您可以使用 loan 指令即時借入大量資金

  • 使用:您可以在同一交易中使用這些借入的資金進行交易、套利或其他操作

  • 還款:在交易結束前,您必須使用 repay 指令償還貸款及支付少量費用

關鍵在於閃電貸款依賴於區塊鏈交易的原子性。如果交易的任何部分失敗(包括還款),整個交易將回滾,彷彿從未發生過。這意味著貸方完全沒有風險:要麼他們得到償還,要麼貸款根本不存在。

在這個挑戰中,您將創建一個簡單的閃電貸款程式,展示指令內省的實際應用。該程式將檢查同一交易中不同指令的指令數據和帳戶,以確保貸款條件得到滿足。

如果你對指令內省(instruction introspection)還不熟悉,我們建議先從指令內省課程開始,以了解此程式中使用的基本概念。

安裝

在開始之前,請確保已安裝 Rust 和 Pinocchio。然後,在終端機中執行以下指令:

# create workspace
cargo new blueshift_pinocchio_flash_loan --lib --edition 2021
cd blueshift_pinocchio_flash_loan

新增 pinocchiopinocchio-systempinocchio-token

cargo add pinocchio pinocchio-system pinocchio-token

Cargo.toml 中宣告 crate 類型,以在 target/deploy 中生成部署工件:

toml
[lib]
crate-type = ["lib", "cdylib"]

現在你已準備好編寫你的閃電貸款程式。

範本

這次,我們將程式分成小而專注的模組,而不是將所有內容放在 lib.rs 中。資料夾結構大致如下:

text
src
├── instructions
│       ├── helpers.rs
│       ├── loan.rs
│       ├── mod.rs
│       └── repay.rs
├── lib.rs

注意:請記得將程式 ID 更改為 22222222222222222222222222222222222222222222,因為我們在底層使用它來測試你的程式。

lib.rs 中的入口點與我們在Pinocchio 入門課程中介紹的內容非常相似。

rust
use pinocchio::{account_info::AccountInfo, entrypoint, program_error::ProgramError, pubkey::Pubkey, ProgramResult};
entrypoint!(process_instruction);

pub mod instructions;
pub use instructions::*;

// 22222222222222222222222222222222222222222222
pub const ID: Pubkey = [
    0x0f, 0x1e, 0x6b, 0x14, 0x21, 0xc0, 0x4a, 0x07, 
    0x04, 0x31, 0x26, 0x5c, 0x19, 0xc5, 0xbb, 0xee, 
    0x19, 0x92, 0xba, 0xe8, 0xaf, 0xd1, 0xcd, 0x07, 
    0x8e, 0xf8, 0xaf, 0x70, 0x47, 0xdc, 0x11, 0xf7, 
];

fn process_instruction(
    _program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    match instruction_data.split_first() {
        Some((Loan::DISCRIMINATOR, data)) => Loan::try_from((data, accounts))?.process(),
        Some((Repay::DISCRIMINATOR, _)) => Repay::try_from(accounts)?.process(),
        _ => Err(ProgramError::InvalidInstructionData)
    }
}

輔助工具

在深入研究 loanrepay 指令之前,讓我們先檢視 helpers.rs

rust
#[repr(C, packed)]
pub struct LoanData {
    pub protocol_token_account: [u8; 32],
    pub balance: u64,
}

pub fn get_token_amount(data: &[u8]) -> u64 {
    if !account.is_owned_by(&pinocchio_token::ID) {
        return Err(PinocchioError::InvalidOwner.into());
    }

    if account.data_len().ne(&pinocchio_token::state::TokenAccount::LEN) {
        return Err(PinocchioError::InvalidAccountData.into());
    }
    
    u64::from_le_bytes(data[64..72].try_into().unwrap())
}

這個檔案非常簡單。它包含一個 LoanData 結構體,我們將用它在貸款償還之前臨時儲存貸款數據。它還提供了一個 get_token_amount() 輔助函數,用於從帳戶中讀取代幣數量。

Next Page借款
或跳過到挑戰
準備好參加挑戰了嗎?
Blueshift © 2025Commit: e573eab