Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Flash Loans

Flash loans let smart contracts borrow any active reserve for a single transaction. The contract must repay the borrowed amount plus a fee before the transaction ends, or the entire transaction reverts.

Two entry points

FunctionReserves per callFee waiver for FLASH_BORROWER_ROLEAllows opening debt
flashLoanOne or manyYes (when msg.sender holds FLASH_BORROWER_ROLE)No (see deviation below)
flashLoanSimpleExactly oneNoNo

flashLoanSimple is cheaper for the common case and skips the multi-asset bookkeeping.

SparkLend deviation from upstream Aave v3

Upstream Aave v3 allows flashLoan callers to convert any leg of the loan into a stable or variable debt position by passing a non-zero interestRateModes[i]. SparkLend disables this. FlashLoanLogic.executeFlashLoan reverts with FLASHLOAN_INTO_BORROW_DEPRECATED if any element of interestRateModes is non-zero (contracts/protocol/libraries/logic/FlashLoanLogic.sol).

The revert is an if/else branch in the post-callback settlement loop, not upfront validation: the receiver's executeOperation runs first, and the transaction reverts when the offending leg is settled.

To take on debt, call Pool.borrow() directly. Flash loans must repay in-transaction, full stop.

Per-reserve preconditions

ValidationLogic.validateFlashloanSimple (called for every flashed asset) checks:

  1. The reserve is not paused (RESERVE_PAUSED).
  2. The reserve is active (RESERVE_INACTIVE).
  3. The reserve has the flash-loan-enabled flag set (FLASHLOAN_DISABLED, error code 91).

The flag is bit 63 of the reserve configuration and is toggled by PoolConfigurator.setReserveFlashLoaning(asset, enabled).

Fees

The flash-loan fee is split between the LPs of the borrowed reserve and the protocol treasury. Both shares are bps and are governance-set via PoolConfigurator.updateFlashloanPremiumTotal and updateFlashloanPremiumToProtocol. Current values can be read from Pool.FLASHLOAN_PREMIUM_TOTAL() and Pool.FLASHLOAN_PREMIUM_TO_PROTOCOL().

For flashLoan (multi-asset), the total fee is waived for msg.senders holding FLASH_BORROWER_ROLE on the ACLManager. For flashLoanSimple, the fee is never waived.

Execution flow

Flash-loan (simple) execution sequence: the receiver contract calls flashLoanSimple on Pool; Pool validates, transfers the underlying out via the AToken, calls executeOperation on the receiver, then pulls amount plus premium back via safeTransferFrom and emits FlashLoan

For the multi-asset variant, the pre-callback transfer and post-callback settlement loop over every entry of assets. The callback signature is executeOperation(address[] assets, uint256[] amounts, uint256[] premiums, address initiator, bytes params) returns (bool).

Receiver contract requirements

Your receiver contract must:

  1. Implement IFlashLoanReceiver (multi-asset) or IFlashLoanSimpleReceiver (single-asset). The executeOperation callback must return true; returning false reverts with INVALID_FLASHLOAN_EXECUTOR_RETURN (error code 13).
  2. Hold or acquire amount + premium of the borrowed asset before executeOperation returns.
  3. Grant Pool an ERC20 allowance for amount + premium of the borrowed asset before returning from executeOperation. The Pool performs safeTransferFrom to settle.

If Pool cannot pull amount + premium, the transaction reverts.

Callers

  • EOA: deploy a contract that implements the receiver interface and call flashLoan / flashLoanSimple on Pool with that contract's address as receiverAddress.
  • Different contract: same pattern; the receiver address is the one implementing executeOperation.
  • Same contract: pass address(this) as receiverAddress. The same contract initiates and receives, then settles.