Quick Start
Add flash loan verification to your Solana program in 3 steps. Works with Anchor and native programs.
1. Install
Add vaea-flash-ctx to your program's Cargo.toml:
toml
[dependencies]
vaea-flash-ctx = "0.1"
No Anchor dependency required. The crate only depends on solana-program.
2. Add Accounts
Your instruction needs two additional accounts: the FlashState PDA and the instructions sysvar.
rust
#[derive(Accounts)]
pub struct MyFlashAction<'info> {
#[account(mut)]
pub user: Signer<'info>,
/// The VAEA FlashState PDA โ read-only
/// CHECK: Ownership and derivation verified by vaea_flash_ctx::verify()
pub flash_state: AccountInfo<'info>,
/// Instructions sysvar for introspection
/// CHECK: Must be sysvar::instructions::ID
#[account(address = anchor_lang::solana_program::sysvar::instructions::ID)]
pub sysvar_instructions: AccountInfo<'info>,
// ... your other accounts
}
3. Call verify()
In your instruction handler, call verify() with the two accounts. It returns a FlashContext with the loan details:
rust
pub fn my_flash_handler(ctx: Context<MyFlashAction>) -> Result<()> {
// Verify flash loan โ 0 CPI, ~2K CU
let flash = vaea_flash_ctx::verify(
&ctx.accounts.flash_state,
&ctx.accounts.sysvar_instructions,
)?;
// Use the verified loan context
msg!("Borrower: {}", flash.payer);
msg!("Amount: {} native of {}", flash.amount, flash.token_mint);
msg!("Fee: {} native", flash.fee);
// Your protocol logic โ full 4-level CPI budget available
// e.g. withdraw, swap, repay, rebalance...
Ok(())
}
๐ก Tip
That's it. Your program can now detect and verify flash loans. The
flash variable contains everything you need โ amount, token, borrower, fee.
Transaction Layout
A flash loan transaction that calls your program looks like this:
text
IX 0: ComputeBudget.set_limit(400_000)
IX 1: VAEA.begin_flash(token, amount) โ creates FlashState PDA
IX 2: YourProtocol.my_flash_handler(...) โ reads PDA, ZERO CPI
IX 3: VAEA.end_flash() โ verifies repayment, closes PDA
The user (or their bot) builds this transaction using the VAEA SDK. Your program only needs to call verify() โ the SDK handles everything else.
Native Program (No Anchor)
If you're not using Anchor, pass the raw AccountInfo references directly:
rust
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, msg};
use vaea_flash_ctx;
pub fn process_instruction(accounts: &[AccountInfo]) -> ProgramResult {
let flash_state = &accounts[0]; // FlashState PDA
let sysvar_ix = &accounts[1]; // Instructions sysvar
let flash = vaea_flash_ctx::verify(flash_state, sysvar_ix)?;
msg!("Flash verified: {} of {}", flash.amount, flash.token_mint);
// Your logic here...
Ok(())
}
Test on Devnet
Deploy your program to devnet and use the VAEA SDK to send a flash loan transaction that calls your program:
typescript
import { VaeaFlash } from '@vaea/flash';
const flash = new VaeaFlash({ connection, wallet });
await flash.executeLocal({
token: 'SOL',
amount: 10,
onFunds: async (ixs) => {
// Add your program's instruction between borrow and repay
ixs.push(myProtocolInstruction);
return ixs;
},
});
If verify() succeeds in the program logs, the integration is working.
โน๏ธ Note
Program ID (devnet): HoYiwkNB7a3gmZXEkTqLkborNDc976vKEUAzBm8YpK5EALT: DjncKSi9KqtnFx6hFYa7ARmwJ7B4Y7UH3XpR2XEuXNJr