Flash Loan
Atomic flash loans with configurable fees and LP share-based liquidity pools
Pending
Anchor 0.32
Program ID
2chVPk6DV21qWuyUA2eHAzATdFSHM7ykv1fVX7Gv6nor
Repository
ExpertVagabond/solana-flash-loan
Default Fee
9 bps (0.09%)
Cluster
Devnet
Instructions
IX
initialize_pool
Creates a new lending pool for a specific SPL token mint.
| Parameter | Type | Description |
|---|---|---|
fee_basis_points | u16 | Flash loan fee in basis points (9 = 0.09%) |
IX
deposit
Deposits tokens into the lending pool, receiving LP shares proportional to the pool value.
| Parameter | Type | Description |
|---|---|---|
amount | u64 | Amount of tokens to deposit |
IX
withdraw
Burns LP shares and returns the proportional token amount (including accrued fees).
| Parameter | Type | Description |
|---|---|---|
shares_to_burn | u64 | Number of LP shares to redeem |
IX
borrow_flash_loan
Borrows tokens atomically from the pool. Creates a receipt PDA that must be closed by repay_flash_loan within the same transaction.
| Parameter | Type | Description |
|---|---|---|
amount | u64 | Amount of tokens to borrow |
IX
repay_flash_loan
Repays the borrowed amount plus fee. Closes the receipt PDA and refunds rent to the borrower. Fee accrues to the pool, increasing LP share value.
| Parameter | Type | Description |
|---|---|---|
| No parameters — reads amount and fee from receipt PDA | ||
IX
update_pool_config
Admin-only instruction to update pool fee or pause/unpause the pool.
| Parameter | Type | Description |
|---|---|---|
new_fee_basis_points | Option<u16> | New fee (0–10000 bps) |
is_active | Option<bool> | Pause or unpause the pool |
Accounts
LendingPool
| Field | Type | Description |
|---|---|---|
admin | Pubkey | Pool creator and admin authority |
token_mint | Pubkey | SPL token mint for this pool |
vault | Pubkey | PDA-owned token vault |
total_deposits | u64 | Total deposits (grows with fees) |
total_shares | u64 | Total LP shares issued |
total_fees_earned | u64 | Lifetime fee counter |
fee_basis_points | u16 | Fee rate (9 = 0.09%) |
is_active | bool | Whether the pool accepts loans |
bump | u8 | PDA bump seed |
DepositReceipt
| Field | Type | Description |
|---|---|---|
pool | Pubkey | Lending pool this deposit belongs to |
depositor | Pubkey | Depositor's wallet |
shares | u64 | LP shares owned |
last_deposit_ts | i64 | Timestamp of last deposit |
bump | u8 | PDA bump seed |
FlashLoanReceipt
| Field | Type | Description |
|---|---|---|
pool | Pubkey | Pool being borrowed from |
borrower | Pubkey | Borrower's wallet |
amount | u64 | Amount borrowed |
fee | u64 | Fee owed |
bump | u8 | PDA bump seed |
PDA Derivation
lending_pool
seeds = [b"lending_pool", token_mint]
pool_vault
seeds = [b"pool_vault", pool]
deposit_receipt
seeds = [b"deposit_receipt", pool, depositor]
flash_loan_receipt
seeds = [b"flash_loan_receipt", pool, borrower]
Error Codes
InvalidFee
Fee must be between 0 and 10000 basis points
InsufficientLiquidity
Not enough tokens in the pool for the requested loan
InvalidAmount
Flash loan amount must be greater than zero
PoolPaused
Pool is paused by admin
Unauthorized
Signer does not match expected authority
MintMismatch
Token mint does not match pool's token mint
MathOverflow
Arithmetic overflow
InsufficientShares
Not enough LP shares for withdrawal
Usage Example
import { getProgram, findLendingPoolPda, findFlashLoanReceiptPda } from "./src"; const flashLoan = getProgram("flashLoan", provider); // Derive PDAs const [poolPda] = findLendingPoolPda(tokenMint); const [receiptPda] = findFlashLoanReceiptPda(poolPda, borrower.publicKey); // Borrow + repay in same transaction const borrowIx = await flashLoan.methods .borrowFlashLoan(new BN(1_000_000)) .accounts({ pool: poolPda, vault, borrowerTokenAccount, borrower: borrower.publicKey }) .instruction(); // ... your arbitrage/swap logic here ... const repayIx = await flashLoan.methods .repayFlashLoan() .accounts({ pool: poolPda, flashLoanReceipt: receiptPda, vault, borrowerTokenAccount }) .instruction(); // Submit as single atomic transaction const tx = new Transaction().add(borrowIx, /* swap ixs */, repayIx);