Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.enso.build/llms.txt

Use this file to discover all available pages before exploring further.

Flashloans let you borrow tokens from a lending protocol without upfront collateral, execute a series of DeFi actions, and repay the debt — all within a single atomic transaction. If any step fails, the entire transaction reverts and no tokens are moved.
Flashloans are only available through the Bundle API. They are not available via the /route endpoint.

How Flashloans Work

  1. You choose the flashloan protocol by setting the action’s protocol field, for example morpho, aave-v3, or balancer-v3
  2. You submit a /bundle request containing a flashloan action with callback actions
  3. The API compiles the bundle into a single transaction
  4. When executed, the FlashloanAdapter requests a flash borrow from the selected lending protocol
  5. The lending protocol transfers the borrowed tokens to the wallet
  6. The callback actions execute sequentially (swaps, deposits, borrows, etc.)
  7. The borrowed amount plus any protocol fee is repaid to the lending protocol
  8. The transaction completes — or reverts entirely if repayment cannot be satisfied
Flashloans are atomic: if any callback action fails or the repayment cannot be satisfied, the entire transaction reverts and no tokens are moved.

Parameters

ParameterTypeDescriptionRequired
flashloanTokenstringAddress of the token to flash borrowYes
flashloanAmountstringAmount to flash borrow in wei (with full decimals)Yes
tokenInstring[]Addresses of additional tokens provided by the user as inputNo
amountInstringAmount of tokenIn provided by the user in weiNo
tokenOutstring[]Addresses of tokens expected as output after callback executionNo
callbackAction[]Array of actions to execute after receiving the flash-borrowed tokensYes
receiverstringAddress to receive output tokens if not the callerNo
The callback actions must produce enough tokens to repay the flash-borrowed amount plus any protocol fee. If repayment cannot be satisfied, the entire transaction will revert.

Supported Protocols

The user must select the flashloan protocol by using one of these slugs as the action’s protocol value.
{
  "protocol": "morpho-markets-v1",
  "action": "flashloan",
  "args": {
    "flashloanToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "flashloanAmount": "1000000000",
    "tokenOut": ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
    "callback": []
  }
}
ProtocolSlugFee
Morphomorpho-markets-v10%
Bend (Morpho fork)bend0%
Dolomitedolomite0%
Aave V3aave-v3Dynamic (pool-specific, basis points from FLASHLOAN_PREMIUM_TOTAL)
Hyperlend (Aave V3 fork)hyperlendDynamic (pool-specific)
Balancer V3balancer-v3Pool-specific fee
Uniswap V3uniswap-v3Pool-specific fee (0.05%, 0.3%, or 1% depending on pool tier)
Kodiak (Uniswap V3 fork)kodiakPool-specific fee

Chain Availability

Not all flashloan protocols are deployed on every chain. The table below shows which protocols are available on each supported chain.
ChainAave V3MorphoBalancer V3DolomiteUniswap V3
Ethereum
Arbitrum
Base
HyperEVM✅ (Hyperlend)
Optimism
Polygon
Berachain✅ (Bend)✅ (Kodiak)
Sonic
Binance
Avalanche
Plasma
Ink
Unichain
World
Soneium
Plume
Katana
Monad
Where a variant is noted (e.g. Hyperlend, Bend, Kodiak), the flashloan uses a fork or alternative deployment of the underlying protocol on that chain.

Routing Strategies

Flashloans are supported across three routing strategies. Each strategy uses a dedicated adapter contract:
StrategyDescriptionAdapter Contract
ensowallet-v2Smart contract wallet — tokens stay in the user’s walletEnsoWalletFlashloanAdapter
routerEOA via EnsoRouter — intermediate tokens held by the routerEnsoRouterFlashloanAdapter
safeGnosis Safe multisig walletEnsoSafeFlashloanAdapter
See the Routing Strategies reference for details on choosing a strategy.

Examples

Morpho WETH/USDC Leveraged Position (Open Loop)

Open a leveraged WETH long against a Morpho Markets V1 (Morpho Blue) market in a single atomic transaction. The user starts with 1 ETH and ends with a Morpho position holding ~1.45 WETH as collateral and 1,800 USDC of debt. The flashloan provides the temporary USDC to swap into extra collateral; the Morpho borrow at the end repays the flashloan from the freshly opened debt position.
morphoWethUsdcLoop.ts
import { EnsoClient } from "@ensofinance/sdk";

const ETHEREUM_ID = 1;
const WALLET_ADDRESS = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";

// Tokens
const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

// Morpho Blue WETH/USDC market on Ethereum
const MORPHO_BLUE = "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb";
const WETH_USDC_MARKET_ID =
  "0x94b823e6bd8ea533b4e33fbc307faea0b307301bc48763acc4d4aa4def7636cd";

const client = new EnsoClient({ apiKey: process.env.ENSO_API_KEY! });

const bundle = await client.getBundleData(
  {
    chainId: ETHEREUM_ID,
    fromAddress: WALLET_ADDRESS,
    receiver: WALLET_ADDRESS,
    routingStrategy: "ensowallet-v2",
  },
  [
    // Step 1: Wrap 1 ETH → WETH (will be combined with the swapped flashloan amount)
    {
      protocol: "wrapped-native",
      action: "deposit",
      args: {
        primaryAddress: WETH,
        tokenIn: NATIVE_TOKEN,
        amountIn: "1000000000000000000", // 1 ETH
        tokenOut: WETH,
      },
    },
    // Step 2: Flashloan 1,800 USDC from Morpho and use it to open the leveraged position
    {
      protocol: "morpho-markets-v1",
      action: "flashloan",
      args: {
        flashloanToken: USDC,
        flashloanAmount: "1800000000", // 1,800 USDC (6 decimals)
        tokenIn: WETH,
        amountIn: { useOutputOfCallAt: 0 }, // 1 WETH from the wrap above
        tokenOut: USDC,
        callback: [
          // 2a: Swap the flashloaned 1,800 USDC into WETH
          {
            protocol: "enso",
            action: "route",
            args: {
              tokenIn: USDC,
              amountIn: "1800000000",
              tokenOut: WETH,
              slippage: 300, // 3%
            },
          },
          // 2b: Read the combined WETH balance (user's 1 WETH + swapped WETH)
          {
            protocol: "enso",
            action: "balance",
            args: { token: WETH },
          },
          // 2c: Deposit all WETH as collateral in the Morpho WETH/USDC market
          {
            protocol: "morpho-markets-v1",
            action: "deposit",
            args: {
              primaryAddress: MORPHO_BLUE,
              positionId: WETH_USDC_MARKET_ID,
              tokenIn: WETH,
              amountIn: { useOutputOfCallAt: 1 },
              onBehalfOf: WALLET_ADDRESS,
            },
          },
          // 2d: Borrow 1,800 USDC against the new collateral — this repays the flashloan
          {
            protocol: "morpho-markets-v1",
            action: "borrow",
            args: {
              primaryAddress: MORPHO_BLUE,
              positionId: WETH_USDC_MARKET_ID,
              collateral: WETH,
              tokenOut: USDC,
              amountOut: "1800000000",
              onBehalfOf: WALLET_ADDRESS,
            },
          },
        ],
      },
    },
  ],
);
Pick the flashloan asset to match the final borrow. Flashloaning USDC and ending the callback with a USDC borrow lets the borrowed USDC repay the flashloan directly — no extra swap needed at the end of the callback.

Alchemix AlchemistV3 alUSD Loop (Morpho Flashloan)

Open an AlchemistV3 alUSD position using a Morpho USDC flashloan. The user contributes 10 MIXUSD; the flashloan brings in 15 USDC of “synthetic” collateral that gets wrapped into 15 MIXUSD inside the callback. The combined 25 MIXUSD becomes AlchemistV3 collateral, against which 17 alUSD is minted and swapped back into the USDC needed to repay the flashloan.
alUsdLoopMorphoFlashloan.ts
import { EnsoClient } from "@ensofinance/sdk";

const ETHEREUM_ID = 1;
const WALLET_ADDRESS = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";

const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const MIXUSD = "0x9B44efCa3e2a707B63Dc00CE79d646E5E5D24bA5"; // alchemix-myts USDC
const ALUSD = "0xbc6da0fe9ad5f3b0d58160288917aa56653660e9";
const ALCHEMIST_V3_USD = "0xeB83112d925268BeDe86654C13D423a987587e3E";

const client = new EnsoClient({ apiKey: process.env.ENSO_API_KEY! });

const bundle = await client.getBundleData(
  {
    chainId: ETHEREUM_ID,
    fromAddress: WALLET_ADDRESS,
    routingStrategy: "router",
  },
  [
    {
      protocol: "morpho-markets-v1",
      action: "flashloan",
      args: {
        flashloanToken: USDC,
        flashloanAmount: "15000000", // 15 USDC (6 decimals)
        tokenIn: [MIXUSD],
        amountIn: ["10000000000000000000"], // 10 MIXUSD provided by the user
        tokenOut: [USDC],
        callback: [
          // 1: Wrap the 15 flashloaned USDC into MIXUSD via alchemix-myts
          {
            protocol: "alchemix-myts",
            action: "deposit",
            args: {
              primaryAddress: MIXUSD,
              tokenIn: USDC,
              tokenOut: MIXUSD,
              amountIn: "15000000",
            },
          },
          // 2: Read total MIXUSD (user's 10 + freshly minted 15)
          {
            protocol: "enso",
            action: "balance",
            args: { token: MIXUSD },
          },
          // 3: Open an AlchemistV3 NFT position with the combined MIXUSD
          {
            protocol: "alchemix-vaults-v3",
            action: "deposit",
            args: {
              primaryAddress: ALCHEMIST_V3_USD,
              tokenIn: MIXUSD,
              tokenOut: ALCHEMIST_V3_USD,
              amountIn: { useOutputOfCallAt: 1 },
              tokenId: "0", // 0 = mint a new position
              receiver: "0x0000000000000000000000000000000000000000",
            },
          },
          // 4: Borrow 17 alUSD against the newly minted NFT
          {
            protocol: "alchemix-vaults-v3",
            action: "borrow",
            args: {
              primaryAddress: ALCHEMIST_V3_USD,
              collateral: ALUSD,
              tokenOut: ALUSD,
              amountOut: "17000000000000000000", // 17 alUSD
              tokenId: { useOutputOfCallAt: 2, index: 0 },
            },
          },
          // 5: Swap 17 alUSD → USDC to repay the flashloan
          {
            protocol: "enso",
            action: "route",
            args: {
              tokenIn: [ALUSD],
              amountIn: { useOutputOfCallAt: 3 },
              tokenOut: [USDC],
              slippage: "100", // 1%
            },
          },
        ],
      },
    },
  ],
);
tokenIn / amountIn on the flashloan action: these are user-contributed assets that flow into the callback alongside the flashloaned funds — tokenIn accepts a single address or an array, and amountIn accepts a single amount, an array, or a useOutputOfCallAt reference to an earlier action’s output.

Uniswap V3 Flashloan Opening an Aave V3 Leveraged Position (eMode)

Open a leveraged Aave V3 position inside a Uniswap V3 flashloan callback on MegaETH. The user contributes 1 USDm collateral and flashloans 1 USDe from a specific Uniswap V3 pool; inside the callback the flashloan is swapped to USDm, deposited as collateral, and Aave V3 mints 1.503 USDe debt (slightly more than 1 to cover the pool fee) to repay the flashloan.
uniswapV3FlashloanAaveLeverage.ts
import { EnsoClient } from "@ensofinance/sdk";

const MEGAETH_ID = 4326;
const WALLET_ADDRESS = "0xc95E8A0c36aBCFB7f436417DF2f1875e6642ad7D";

// Tokens on MegaETH
const USDE = "0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7"; // flashloan asset (= Aave debt asset)
const USDM = "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34"; // user input + Aave collateral
const AUSDM = "0x78f2cB75D664d6f71433174056c25A5958B4016F"; // Aave aToken receipt

// Uniswap V3 pool used as the flashloan source and the Aave V3 pool
const UNI_V3_POOL = "0x587F6eeAfc7Ad567e96eD1B62775fA6402164b22";
const AAVE_V3_POOL = "0x7e324AbC5De01d112AfC03a584966ff199741C28";

const client = new EnsoClient({ apiKey: process.env.ENSO_API_KEY! });

const bundle = await client.getBundleData(
  {
    chainId: MEGAETH_ID,
    fromAddress: WALLET_ADDRESS,
    receiver: WALLET_ADDRESS,
    spender: WALLET_ADDRESS,
    routingStrategy: "ensowallet-v2",
  },
  [
    {
      protocol: "uniswap-v3",
      action: "flashloan",
      args: {
        primaryAddress: UNI_V3_POOL, // Uniswap V3 pool to flashloan from
        flashloanToken: USDE,
        flashloanAmount: "1000000000000000000", // 1 USDe
        tokenIn: USDM,
        amountIn: "1000000000000000000", // 1 USDm contributed by the user
        tokenOut: USDE,
        receiver: WALLET_ADDRESS,
        callback: [
          // 1: Swap the flashloaned 1 USDe into USDm
          {
            protocol: "enso",
            action: "route",
            args: {
              tokenIn: USDE,
              tokenOut: USDM,
              amountIn: "1000000000000000000",
            },
          },
          // 2: Read combined USDm balance (user's 1 + swapped)
          {
            protocol: "enso",
            action: "balance",
            args: { token: USDM },
          },
          // 3: Deposit USDm as collateral into Aave V3
          {
            protocol: "aave-v3",
            action: "deposit",
            args: {
              primaryAddress: AAVE_V3_POOL,
              tokenIn: USDM,
              tokenOut: AUSDM,
              amountIn: { useOutputOfCallAt: 1 },
              onBehalfOf: WALLET_ADDRESS,
            },
          },
          // 4: Borrow 1.503 USDe — repays the flashloan + Uniswap V3 pool fee
          {
            protocol: "aave-v3",
            action: "borrow",
            args: {
              primaryAddress: AAVE_V3_POOL,
              collateral: USDM,
              tokenOut: USDE,
              amountOut: "1503000000000000000", // 1.503 USDe
              onBehalfOf: WALLET_ADDRESS,
              args: {
                eModeCategoryId: "7", // required by Aave V3 for this borrow path
              },
            },
          },
        ],
      },
    },
  ],
);
Uniswap V3 flashloans require primaryAddress: unlike Morpho or Aave V3 (where the lender is global), Uniswap V3 flashloans borrow from a specific pool. Pass the pool address as primaryAddress and pay the pool’s fee tier (0.05% / 0.3% / 1%) when repaying — over-borrow slightly in the final borrow action to cover it.
Aave V3 eMode: when the borrow target sits in an eMode category, pass args.eModeCategoryId on the aave-v3.borrow action. Enso emits the matching setUserEMode approval automatically.

Updated