The Bundle API supports a variety of actions to build complex DeFi strategies. This reference guide explains all available actions and their parameters.

To get the up-to date list of available actions and parameters, use GET /integration/actions.
To get a list of actions available for a specific protocol, use GET standards/{slug}/.

Chaining Actions

Bundle API allows using output of one action as the input for another.

To reference outputs from previous actions use the useOutputOfCallAt syntax. For array-outputs such as split, you can specify the index within that action’s output array

{
  "amountIn": {
    "useOutputOfCallAt": 0 // Use the output amount from the action at index 0
    "index": 1 // Optional: access outputOfCallAt[0][1]
  }
}

Here’s an example of a more complex chaining sequence that splits WETH into three different portions:

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate"
  },
  [
    {
      protocol: "enso",
      action: "route",
      args: {
        tokenIn: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
        tokenOut: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        amountIn: "1000000000" // 1000 USDC
      }
    },
    {
      protocol: "aave-v3",
      action: "deposit",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        amountIn: { "useOutputOfCallAt": 1, "index": 0 }, // First portion
        primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2" // Aave V3 pool
      }
    },
    {
      protocol: "curve",
      action: "deposit",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        amountIn: { "useOutputOfCallAt": 1, "index": 1 }, // Second portion
        primaryAddress: "0xDC24316b9AE028F1497c275EB9192a3Ea0f67022" // Curve ETH/stETH pool
      }
    },
    {
      protocol: "yearn",
      action: "deposit",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        amountIn: { "useOutputOfCallAt": 1, "index": 2 }, // Third portion
        primaryAddress: "0xa258C4606Ca8206D8aA700cE2143D7db854D168c" // Yearn WETH vault
      }
    }
  ]
);

Slippage Protection

Whereas the route action includes configurable slippage protection by default, but other actions require manual slippage configuration.

Always include slippage protection via the slippage or minAmountOut actions to prevent price impact.

slippage

Applies slippage protection specified in basis points (bps) to ensure the received amount is within the acceptable range of the expected output.

The action calculates the minimum acceptable amount based on the specified slippage tolerance (amountOut * (10000 - bps) / 10000). If the actual received amount falls below this threshold, the transaction will revert.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    {
      protocol: "enso",
      action: "slippage",
      args: {
        bps: "100", // 1% maximum slippage (100 basis points)
        amountOut: { useOutputOfCallAt: 0 }, // Reference previous action's output
      },
    },
    {
      protocol: "uniswap-v2",
      action: "swap",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amountIn: "1000000000000000000", // 1 WETH
        primaryAddress: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", // Uniswap V2 Router
        receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      },
    },
  ],
);
ParameterDescriptionRequired
amountOutExpected output amount - must be output of one of previous actions useOutputOfCallAtYes
bpsMaximum acceptable slippage in basis points (1 bps = 0.01%, 100 bps = 1%)Yes

minAmountOut

Applies slippage protection specified in absolute amount (minAmountOut) to ensure the received amount is within the acceptable range of the expected output.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    // First action to get an output
    {
      protocol: "uniswap-v2",
      action: "swap",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amountIn: "1000000000000000000", // 1 WETH
        primaryAddress: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", // Uniswap V2 Router
        receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      },
    },
    // Now apply minAmountOut check
    {
      protocol: "enso",
      action: "minamountout",
      args: {
        amountOut: { useOutputOfCallAt: 0 }, // Reference to first action's output
        minAmountOut: "1940000000", // Minimum amount (1.94 USDC)
      },
    },
  ],
);
ParameterDescriptionRequired
amountOutExpected output amount - must be output of one of previous actions useOutputOfCallAtYes
minAmountOutMinimum acceptable amount of out tokenYes

Core Actions

route

The route action determines the optimal path to swap one token for another across multiple DeFi protocols supported by Enso.

This action gets expanded into a combination of swap, deposit, and redeem actions, similar to /route API. The /bundle API will return a route object that contains a list of all such actions.

When using the route action, slippage is automatically calculated and applied. The action will revert if the received amount is below the expected output after applying slippage.

For other actions, make sure to add one of slippage protection actions

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "route",
          args: {
            tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH address
            tokenOut: "0xae7ab96520de3a18e5e111b5eaab095312d7fe84", // stETH address
            amountIn: "1000000000000000000", // Amount in wei (1 ETH)
            slippage: "300", // 3% slippage tolerance (in basis points)
            receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver address
            primaryAddress: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", // Optional: Primary contract address
            poolFee: "3000", // Optional: Pool fee in basis points (e.g., 3000 for 0.3%)
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of the token to send. For ETH, use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeYes
tokenOutAddress of the token to receiveYes
amountInAmount of tokenIn to send in wei (with full decimals)Yes
slippageSlippage tolerance in basis points (100 = 1%)No
receiverAddress to receive the output tokens if not the callerNo
primaryAddressOptional address of the router or primary contract to useNo
poolFeeOptional pool fee in basis points when using specific poolsNo

swap

Swaps one token for another using a specific pool or exchange protocol.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "uniswap-v2",
          action: "swap",
          args: {
            tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
            tokenOut: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
            amountIn: "1000000000000000000", // 1 WETH (18 decimals)
            primaryAddress: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", // Uniswap V2 Router
            receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Receiver
            slippage: "100", // Optional: 1% slippage (100 basis points)
            poolFee: "3000", // Optional: Pool fee in basis points (e.g., 3000 for 0.3%)
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of token to swap fromYes
tokenOutAddress of token to swap toYes
amountInAmount of tokenIn to swap in wei (with full decimals)Yes
primaryAddressAddress of the router or pool contractNo
receiverAddress to receive the output tokensYes
slippageSlippage tolerance in basis points (100 = 1%)No
poolFeeOptional pool fee in basis points when using specific poolsNo

deposit

Deposits tokens into a protocol to receive a position token or add liquidity.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "aave-v3",
          action: "deposit",
          args: {
            tokenIn: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address
            tokenOut: "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8", // aWETH address (optional)
            amountIn: "1000000000000000000", // Amount in wei (1 WETH)
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", // Aave V3 pool
            receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver address
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of token to deposit. Can be a single address or an array for multiple tokensYes
tokenOutAddress of token to receive. Can be a single address or an array for multiple tokensNo
amountInAmount of tokenIn to deposit in wei (with full decimals). Can be a single value or an array for multiple tokensYes
primaryAddressAddress of the protocol contract to interact withYes
receiverAddress to receive the output tokens if not the callerNo

redeem

Redeems underlying assets from a protocol by exchanging shares or tokens. Use it to exit a position and retrieve the desired tokens.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        // Step 1: First deposit into the ERC4626 vault to get shares
        {
          protocol: "erc4626",
          action: "deposit",
          args: {
            tokenIn: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI (underlying asset)
            tokenOut: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // yvDAI (vault shares)
            amountIn: "1000000000000000000", // 1 DAI
            primaryAddress: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // Vault address
          },
        },
        // Step 2: Now redeem the shares we just received
        {
          protocol: "erc4626",
          action: "redeem",
          args: {
            tokenIn: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // yvDAI shares
            tokenOut: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI (underlying asset)
            amountIn: { useOutputOfCallAt: 0 }, // Use the shares from the deposit
            primaryAddress: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // Vault address
            receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of shares/tokens to redeemNo
tokenOutAddress of token(s) to receive upon redemption. Can be a single address or an arrayYes
amountInAmount of shares/tokens to redeem in wei (with full decimals)Yes
primaryAddressAddress of the contract to interact withYes
receiverAddress to receive the output tokens if not the callerNo

Deposit & Redeem Actions

depositCLMM

Deposits tokens into a Concentrated Liquidity Market Maker pool (like Uniswap V3).

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11",
        spender: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11",
        routingStrategy: "router",
      },
      [
        {
          protocol: "uniswap-v4",
          action: "depositclmm",
          args: {
            tokenOut: "0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e",
            ticks: [-887270, 887270],
            tokenIn: [
              "0xdac17f958d2ee523a2206206994597c13d831ec7", // USDT
              "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", // WBTC
            ],
            poolFee: "500",
            amountIn: ["1000000000", "100000000"], // 1000 USDT (6 decimals), 1 WBTC (8 decimals)
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInArray of addresses of tokens to deposit (usually 2 tokens)Yes
tokenOutAddress of the position NFT to receiveYes
amountInArray of amounts to deposit in wei (with full decimals). Must match the length of tokenIn arrayYes
ticksArray containing lower and upper tick bounds defining the price rangeYes
poolFeePool fee tier in basis points (e.g., 3000 for 0.3%)Yes
receiverAddress to receive the position NFT if not the callerNo

redeemCLMM

Redeems tokens from a Concentrated Liquidity Market Maker position (like Uniswap V3).

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "uniswap-v3",
          action: "redeemclmm",
          args: {
            tokenIn: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", // UNI-V3-POS NFT
            tokenOut: [
              "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
              "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
            ],
            liquidity: "1000000000000", // Liquidity amount to withdraw
            tokenId: "123456", // The NFT token ID
            receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of the position NFT tokenYes
tokenOutArray of addresses of tokens to receiveYes
liquidityAmount of liquidity to withdrawYes
tokenIdID of the position NFTYes
receiverAddress to receive the underlying tokens if not the callerNo

singleDeposit

Deposits a single token into a protocol. This is a specialized version of the deposit action for single token deposits.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    {
      protocol: "yearn",
      action: "singledeposit",
      args: {
        tokenIn: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI address
        tokenOut: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // yvDAI address
        amountIn: "10000000000000000000", // 10 DAI (18 decimals)
        primaryAddress: "0xdA816459F1AB5631232FE5e97a05BBBb94970c95", // Yearn vault
        receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver
      },
    },
  ],
);
ParameterDescriptionRequired
tokenInAddress of the single token to depositYes
tokenOutAddress of the token to receive (usually a receipt or share token)No
amountInAmount of tokenIn to deposit in wei (with full decimals)Yes
primaryAddressAddress of the protocol contract to interact withYes
receiverAddress to receive the output tokens if not the callerNo

multiDeposit

Deposits multiple tokens into a protocol (like Curve or Balancer) in a single operation.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    {
      protocol: "curve",
      action: "multideposit",
      args: {
        tokenIn: [
          "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI
          "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
          "0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
        ],
        tokenOut: "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490", // 3Crv LP token
        amountIn: [
          "10000000000000000000", // 10 DAI (18 decimals)
          "10000000", // 10 USDC (6 decimals)
          "10000000", // 10 USDT (6 decimals)
        ],
        primaryAddress: "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", // Curve 3pool
        receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver
      },
    },
  ],
);
console.log(JSON.stringify(bundle, null, 2));
ParameterDescriptionRequired
tokenInArray of addresses of tokens to depositYes
tokenOutAddress of the LP token or receipt token to receiveNo
amountInArray of amounts to deposit in wei (with full decimals). Must match the length of tokenIn arrayYes
primaryAddressAddress of the pool or protocol contract to interact withYes
receiverAddress to receive the LP tokens if not the callerNo

tokenizedSingleDeposit

Deprecation Notice: This action is deprecated in favor of using singleDeposit with the appropriate protocol. It will be removed in a future API version.

Deposits a single token and receives a tokenized position.

{
  "protocol": "compound-v3",
  "action": "tokenizedsingledeposit",
  "args": {
    "tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
    "tokenOut": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", // cUSDCv3
    "amountIn": "10000000", // 10 USDC (6 decimals)
    "primaryAddress": "0xc3d688B66703497DAA19211EEdff47f25384cdc3", // Compound market
    "receiver": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" // Optional: Receiver
  }
}
ParameterDescriptionRequired
tokenInAddress of token to depositYes
tokenOutAddress of tokenized position to receiveYes
amountInAmount of tokenIn to deposit in wei (with full decimals)Yes
primaryAddressAddress of the protocol contract to interact withYes
receiverAddress to receive the position tokens if not the callerNo

tokenizedMultiDeposit

Deprecation Notice: This action is deprecated in favor of using multiDeposit with the appropriate protocol. It will be removed in a future API version.

Deposits multiple tokens and receives a tokenized position.

{
  "protocol": "balancer-v2",
  "action": "tokenizedmultideposit",
  "args": {
    "tokenIn": [
      "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC
      "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"  // WETH
    ],
    "tokenOut": "0x8353157092ED8Be69a9DF8F95af097bbF33Cb2aF", // BPT token
    "amountIn": [
      "100000", // 0.01 WBTC (8 decimals)
      "10000000000000000" // 0.01 WETH (18 decimals)
    ],
    "primaryAddress": "0x8353157092ED8Be69a9DF8F95af097bbF33Cb2aF", // Balancer Pool
    "receiver": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e" // Optional: Receiver
  }
}
ParameterDescriptionRequired
tokenInArray of addresses of tokens to depositYes
tokenOutAddress of the tokenized position to receiveYes
amountInArray of amounts to deposit in wei (with full decimals). Must match the length of tokenIn arrayYes
primaryAddressAddress of the protocol contract to interact withYes
receiverAddress to receive the position token if not the callerNo

multiOutSingleDeposit

Deposits a single token and receives multiple output tokens (typically used for certain AMM positions).

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    {
      protocol: "uniswap-v3",
      action: "multioutsingledeposit",
      args: {
        tokenIn: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        tokenOut: [
          "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", // WBTC
          "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        ],
        amountIn: "1000000000000000000", // 1 WETH (18 decimals)
        primaryAddress: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", // Uniswap pool
        receiver: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", // Optional: Receiver
      },
    },
  ],
);
console.log(JSON.stringify(bundle, null, 2));
ParameterDescriptionRequired
tokenInAddress of the single token to depositYes
tokenOutArray of addresses of tokens to receiveYes
amountInAmount of tokenIn to deposit in wei (with full decimals)Yes
primaryAddressAddress of the protocol contract to interact withYes
receiverAddress to receive the output tokens if not the callerNo

Lending Actions

borrow

Borrows a token from a lending protocol using a deposited token as collateral.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "aave-v3",
          action: "deposit",
          args: {
            tokenIn: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address
            tokenOut: "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8", // aWETH address (optional)
            amountIn: "1000000000000000000", // Amount in wei (1 WETH)
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", // Aave V3 pool
            receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Optional: Receiver address
          },
        },
        {
          protocol: "aave-v3",
          action: "borrow",
          args: {
            collateral: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address (collateral)
            tokenOut: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC address (to borrow)
            amountOut: "1000000000", // Amount to borrow in wei (1000 USDC with 6 decimals)
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", // Aave V3 pool
          },
        },
      ],
    );
ParameterDescriptionRequired
collateralAddress of the token used as collateral. Can be an array for multiple collateral tokensYes
tokenOutAddress of the token to borrowYes
amountOutAmount to borrow in wei (with full decimals)Yes
primaryAddressAddress of the lending pool contractYes

repay

Repays a loan on a lending protocol.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "aave-v3",
          action: "deposit",
          args: {
            tokenIn: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address
            tokenOut: "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8", // aWETH address (optional)
            amountIn: "1000000000000000000", // Amount in wei (1 WETH)
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", // Aave V3 pool
            receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Optional: Receiver address
          },
        },
        {
          protocol: "aave-v3",
          action: "borrow",
          args: {
            collateral: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address (collateral)
            tokenOut: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC address (to borrow)
            amountOut: "1000000000", // Amount to borrow in wei (1000 USDC with 6 decimals)
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", // Aave V3 pool
          },
        },
        // Step 3: Now repay the borrowed USDT
        {
          protocol: "aave-v3",
          action: "repay",
          args: {
            tokenIn: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
            amountIn: "1000000000", // 100 USDC
            primaryAddress: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInAddress of token to repayYes
amountInAmount to repay in wei (with full decimals)Yes
primaryAddressAddress of the lending pool contractYes
onBehalfOfAddress to repay debt forYes

repay on Behalf of Another address

Repay parameter onBehalfOf enables you to repay a loan on behalf of a given address:


const bundleData = await client.getBundleData(
  {
    chainId: 1, // Mainnet
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045" as Address,
    routingStrategy: "delegate",
  },
  [
    // 3. Repay the ETH debt
    {
      protocol: "compound-v2",
      action: "repay",
      args: {
        tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH
        amountIn: "300000000000000000",
        primaryAddress: "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", // cETH contract
        onBehalfOf: "0x80fCBfbC698Aca3B3BCB83ceB13301a639A39832",
      },
    },
  ],
);

console.log(bundleData);

Yield Farming Actions

harvest

Harvests rewards from yield-generating positions.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "curve-gauge",
          action: "harvest",
          args: {
            token: "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", // Token address (LP token or gauge token)
            primaryAddress: "0x182B723a58739a9c974cFDB385ceaDb237453c28", // Curve gauge address
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of token to harvest rewards forYes
primaryAddressAddress of the contract to interact with (e.g., gauge, farm)Yes

Token Management Actions

approve

Approves a spender to use tokens.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "erc20",
          action: "approve",
          args: {
            token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH address
            spender: "0xe592427a0aece92de3edee1f18e0157c05861564", // Spender address (e.g., Uniswap router)
            amount: "1000000000000000000000000", // Amount to approve in wei (1M WETH)
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of the token to approveYes
spenderAddress of the spender (protocol or router)Yes
amountAmount to approve in wei (with full decimals)Yes

transfer

Transfers tokens to a specified address.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "erc20",
          action: "transfer",
          args: {
            token: "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", // OMG token address
            receiver: "0x80eba3855878739f4710233a8a19d89bdd2ffb8e", // Recipient address
            amount: "1000000000000000000", // Amount to transfer in wei (1 OMG)
            id: "1234", // Optional: ID for ERC721 or ERC1155 tokens
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of the token to transferYes
receiverAddress of the recipientYes
amountAmount to transfer in wei (with full decimals)Yes
idToken ID for ERC721 or ERC1155 tokensNo

transferFrom

Transfers tokens from a specified address to another address.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "balance",
          args: {
            token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
          },
        },
        {
          protocol: "erc20",
          action: "transferfrom",
          args: {
            token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // OMG token address
            sender: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Sender address
            receiver: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11", // Recipient address
            amount: "1000000000000000000", // Amount to transfer in wei (1 OMG)
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of the token to transferYes
senderAddress of the senderYes
receiverAddress of the recipientYes
amountAmount to transfer in wei (with full decimals)Yes
idToken ID for ERC721 or ERC1155 tokensNo

permitTransferFrom

Approves and transfers a token that supports permit in a single step using a signature. A permit signature needs to be generated offchain and passed to the API.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "permit2",
          action: "permittransferfrom",
          args: {
            token: "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", // Token address
            amount: "1000000000000000000", // Amount in wei (1 token)
            sender: "0xb67f3CE46bB9E1a1127796c27f38DbaB9f643ec0", // Sender address
            receiver: "0x35a2839b617F7da6534d636f22945f6Cb6137130", // Receiver address
            nonce: "1", // Nonce to prevent replay attacks
            deadline: "1710150268", // Timestamp deadline for signature validity
            signature: "0x...", // Permit signature
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of the token to transfer. Can be an array for multiple tokensYes
amountAmount to transfer in wei (with full decimals). Can be an array for multiple tokensYes
senderAddress of the senderYes
receiverAddress of the recipientYes
nonceNonce value to prevent signature replayYes
deadlineTimestamp after which the signature is invalidYes
signatureThe EIP-2612 permit signatureYes

Bridging

bridge

Facilitates cross-chain token transfers using various bridge protocols with optional callback actions on the destination chain.

When used with callback actions (callback array), it can automatically execute a series of actions on the destination chain once tokens arrive.

Important: When using callbacks, the callback bundle MUST start with a balance action to check the bridged token balance on the destination chain. Callbacks can reference outputs from previous callback actions using the useOutputOfCallAt syntax to create complex cross-chain operations. Each callback action is executed sequentially on the destination chain.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11",
    spender: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11",
    routingStrategy: "router",
  },
  [
    {
      protocol: "enso",
      action: "route",
      args: {
        tokenIn: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC on mainnet
        amountIn: "1000000000", // 1000 USDC
        tokenOut: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH
      },
    },
    {
      protocol: "enso",
      action: "fee",
      args: {
        token: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
        amount: { useOutputOfCallAt: 0 },
        bps: 25,
        receiver: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11", // Fee receiver
      },
    },
    {
      protocol: "stargate",
      action: "bridge",
      args: {
        primaryAddress: "0x77b2043768d28e9c9ab44e1abfc95944bce57931",
        destinationChainId: 8453,
        tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
        amountIn: { useOutputOfCallAt: 1 },
        receiver: "0x93621DCA56fE26Cdee86e4F6B18E116e9758Ff11",
        callback: [
          {
            protocol: "enso",
            action: "balance",
            args: {
              token: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
            },
          },
          {
            protocol: "enso",
            action: "split",
            args: {
              tokenIn: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
              tokenOut: [
                "0x50c5725949a6f0c72e6c4a641f24049a917db0cb",
                "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
              ],
              amountIn: { useOutputOfCallAt: 0 },
            },
          },
          {
            protocol: "enso",
            action: "slippage",
            args: {
              amountOut: { useOutputOfCallAt: 1, index: 0 },
              bps: 50,
            },
          },
          {
            protocol: "enso",
            action: "slippage",
            args: {
              amountOut: { useOutputOfCallAt: 1, index: 1 },
              bps: 50,
            },
          },
          {
            protocol: "uniswap-v4",
            action: "depositclmm",
            args: {
              tokenOut: "0x7c5f5a4bbd8fd63184577525326123b519429bdc",
              ticks: [-276842, -275842],
              tokenIn: [
                "0x50c5725949a6f0c72e6c4a641f24049a917db0cb",
                "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
              ],
              poolFee: "100",
              amountIn: [
                { useOutputOfCallAt: 1, index: 0 },
                { useOutputOfCallAt: 1, index: 1 },
              ],
            },
          },
          {
            protocol: "enso",
            action: "slippage",
            args: {
              amountOut: { useOutputOfCallAt: 4 },
              bps: 200,
            },
          },
        ],
      },
    },
  ],
);
ParameterDescriptionRequired
primaryAddressSource bridge pool addressYes
destinationChainIdTarget blockchain network IDYes
tokenInToken address to bridge from source chainYes
amountInAmount to bridge (with full decimals) or a reference to a previous action’s outputYes
receiverAddress to receive bridged tokens on destination chainYes
callbackArray of actions to execute on the destination chain after bridging (must start with balance action)No

Utility Actions

balance

Gets the balance of a token for the caller’s address.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "balance",
          args: {
            token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenAddress of the token to check balanceYes

split

Splits a token into multiple outputs with specified token addresses and amounts.

const bundle = await client.getBundleData(
  {
    chainId: 1,
    fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
    routingStrategy: "delegate",
  },
  [
    {
      protocol: "enso",
      action: "balance",
      args: {
        token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
      },
    },
    {
      protocol: "enso",
      action: "split",
      args: {
        tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        tokenOut: [
          "0x6b175474e89094c44da98b954eedeac495271d0f", // USDC
          "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
        ],
        amountIn: { useOutputOfCallAt: 0 }, // Use the balance from the first action
      },
    },
  ],
);
ParameterDescriptionRequired
tokenInAddress of the token to splitYes
tokenOutArray of token addresses for the split outputsYes
amountInAmount to split in wei (with full decimals)Yes
receiverAddress to receive the split tokensNo

merge

Merge multiple token inputs into a single output.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "merge",
          args: {
            tokenIn: [
              "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
              "0x6b175474e89094c44da98b954eedeac495271d0f", // DAI
            ],
            tokenOut: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // Combined WETH
            amountIn: [
              "2000000000000000000000", // 2 USDC
              "3000000000000000000000", // 3 DAI
            ],
            receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenInArray of input token addressesYes
tokenOutAddress of the output tokenYes
amountInArray of amounts to merge (must be in the same denomination)Yes
receiverAddress to receive the merged tokensNo

call

Makes an arbitrary call to any contract, allowing for custom interactions. This is useful for executing complex logic or interacting with contracts that are not directly supported by the Enso API.

For example, to perform arithemtics over return values from previous actions, you can use the PercentageMathHelpers contract:

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "call",
          args: {
            address: "0xD0aF6F692bFa10d6a535A3A321Dc8377F4EeEF12", // Contract address
            method: "percentMul", // Method name
            abi: "function percentMul(uint256,uint256) external", // ABI signature
            args: [
              "1000000000000000000", // 1 ETH (first argument)
              "7000", // 70% (second argument)
            ],
          },
        },
      ],
    );
ParameterDescriptionRequired
addressAddress of the contract to callYes
methodName of the method to callYes
abiABI signature of the methodYes
argsArray of arguments to pass to the methodYes

fee

Calculates and deducts a fee from a specified amount, sending the fee to a designated receiver. This action is typically prepended to bridge operations to facilitate fee collection.

The fee action calculates the fee as amount * (bps/10000) and sends this amount to the receiver. It returns amount - fee, which can be used in subsequent actions via useOutputOfCallAt.

const bundle = await client.getBundleData(
      {
        chainId: 1,
        fromAddress: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        routingStrategy: "delegate",
      },
      [
        {
          protocol: "enso",
          action: "fee",
          args: {
            token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
            amount: "1000000000000",
            bps: "500",
            receiver: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
          },
        },
      ],
    );
ParameterDescriptionRequired
tokenToken address to apply the fee toYes
amountAmount to apply the fee to (with full decimals) or a return value from a previous actionYes
bpsFee percentage in basis points (1 bps = 0.01%, 100 bps = 1%)Yes
receiverAddress to receive the feeYes

Protocol Support

The Bundle API supports a wide range of protocols. Some common ones include:

  • aave-v2, aave-v3: Aave lending/borrowing
  • balancer-v2: Balancer liquidity pools
  • curve: Curve Finance stable swaps and gauges
  • curve-gauge: Curve gauges for staking
  • erc20: Standard token operations
  • erc4626: ERC4626 vaults
  • enso: General Enso operations including route and arbitrary calls
  • permit2: Uniswap’s Permit2 operations
  • uniswap-v2, uniswap-v3: Uniswap pools and routers
  • yearn: Yearn Finance vaults
  • compound-v2, compound-v3: Compound lending/borrowing
  • stargate: Cross-chain bridging

For a complete list of supported protocols, use the Projects API endpoint: GET /standards.

Updated