amount + fee before the call returns. Read first: Strategies, Security model.
Call the controller; it issues one pool flash_loan. The pool sends amount to your receiver, runs the callback, then pulls amount + fee back in the same call. The controller emits FlashLoanEvent.
Goal
Obtainamount of a flashloanable asset, run your logic in a receiver contract, and have the pool reclaim amount + fee in the same transaction.
Preconditions
assetis a listed,Activemarket withis_flashloanable = true(else#401 FlashloanNotEnabled).receiveris a deployed Wasm contract (else#412 InvalidFlashloanReceiver) that exportsexecute_flash_loan.- The pool holds at least
amountof free liquidity. amount > 0(else#14 AmountMustBePositive).- No flash loan is already in progress for this transaction (the
FlashLoanOngoingreentry guard, else#400).
Inputs
Initiator. Authorizes the flash loan. Need not be the receiver.
The flashloanable asset to borrow.
Borrowed amount in asset-native units. Must be positive.
The contract that receives
amount, runs execute_flash_loan, and approves repayment.Opaque payload forwarded verbatim to the receiver’s callback. Encode whatever your receiver needs.
Fee
The fee isflashloan_fee_bps * amount from the asset’s config, with a floor of 1 unit whenever the configured rate is nonzero. Configured values come from the launched market configuration; non-flashloanable assets reject flash loans. The fee is retained by the pool as protocol revenue, later claimable through the controller.
Receiver contract
Your receiver is a separate contract that must export:amount to the receiver. Before the callback returns, the receiver must approve the pool to pull amount + fee of asset — repayment is a transfer_from the pool performs, not an ERC-20-style allowance you set ahead of time. Authorize that approval as the current contract.
transfer_from reclaims less than amount + fee and the call reverts with #402 InvalidFlashloanRepay. The pool also asserts the receiver did not otherwise change the pool balance during the callback.
Build the call
Authorize
caller.require_auth() runs inside the controller’s flash_loan. The cross-contract authorization that matters is the receiver authorizing the pool’s transfer_from during the callback — handled inside execute_flash_loan with authorize_as_current_contract, not by the top-level signer. The payout (pool → receiver) is pool-internal. Simulating the transaction discovers and attaches the auth tree; sign the outer call with the caller key.
Reentry. While the callback runs, the controller holds the FlashLoanOngoing guard. Any attempt to call back into a mutating controller entrypoint — supply, borrow, withdraw, repay, liquidate, a strategy, or another flash_loan — reverts with #400 FlashLoanOngoing.
Verify
On success the controller emitsFlashLoanEvent — topics ["position", "flash_loan"], data { asset, receiver, caller, amount, fee } — and UpdateMarketStateBatchEvent (["market", "batch_state_update"]) reflecting the fee booked as revenue.
Confirm the fee landed with the pool view protocol_revenue(asset) (up by fee), and check your receiver’s token balance returned to its pre-loan level (it paid back amount + fee).
Failure modes
| Error | Cause | Fix |
|---|---|---|
#401 FlashloanNotEnabled | Asset config has is_flashloanable = false | Use a flashloanable asset (for example USDC, XLM, EURC, BTC, ETH on mainnet). |
#412 InvalidFlashloanReceiver | receiver is not a deployed Wasm contract | Pass a deployed contract address that exports execute_flash_loan. |
#402 InvalidFlashloanRepay | Receiver approved less than amount + fee, or changed the pool balance | Approve exactly amount + fee to the pool before the callback returns. |
#400 FlashLoanOngoing | Reentry into a mutating controller entrypoint during the callback | Do not call back into the controller; do your work, then repay. |
#14 AmountMustBePositive | amount is zero or negative | Borrow a positive amount. |
Strategy borrow vs flash loan
Strategy flows (multiply, migrate_from_blend) borrow through pool.create_strategy, not the flash-loan receiver pattern:
| Mechanism | flash_loan | Strategy borrow |
|---|---|---|
| Pool call | pool.flash_loan → receiver callback | pool.create_strategy |
| Fee | Configured bps | 0 for migration; configured for multiply |
| Debt outcome | Repaid in same callback | Permanent account debt |
| Solvency check | At callback end | At strategy_finalize |
Next
Strategies
Leverage and swap flows that build on the flash loan plus the swap aggregator.
Controller ABI
Every controller entrypoint, grouped by access control.

