The Bundle API supports a variety of actions to build complex DeFi strategies.
This reference guide explains all available actions and their parameters.
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",
},
},
],
);
Parameter | Description | Required |
---|
amountOut | Expected output amount - must be output of one of previous actions useOutputOfCallAt | Yes |
bps | Maximum 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)
},
},
],
);
Parameter | Description | Required |
---|
amountOut | Expected output amount - must be output of one of previous actions useOutputOfCallAt | Yes |
minAmountOut | Minimum acceptable amount of out token | Yes |
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%)
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of the token to send. For ETH, use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee | Yes |
tokenOut | Address of the token to receive | Yes |
amountIn | Amount of tokenIn to send in wei (with full decimals) | Yes |
slippage | Slippage tolerance in basis points (100 = 1%) | No |
receiver | Address to receive the output tokens if not the caller | No |
primaryAddress | Optional address of the router or primary contract to use | No |
poolFee | Optional pool fee in basis points when using specific pools | No |
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%)
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of token to swap from | Yes |
tokenOut | Address of token to swap to | Yes |
amountIn | Amount of tokenIn to swap in wei (with full decimals) | Yes |
primaryAddress | Address of the router or pool contract | No |
receiver | Address to receive the output tokens | Yes |
slippage | Slippage tolerance in basis points (100 = 1%) | No |
poolFee | Optional pool fee in basis points when using specific pools | No |
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
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of token to deposit. Can be a single address or an array for multiple tokens | Yes |
tokenOut | Address of token to receive. Can be a single address or an array for multiple tokens | No |
amountIn | Amount of tokenIn to deposit in wei (with full decimals). Can be a single value or an array for multiple tokens | Yes |
primaryAddress | Address of the protocol contract to interact with | Yes |
receiver | Address to receive the output tokens if not the caller | No |
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
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of shares/tokens to redeem | No |
tokenOut | Address of token(s) to receive upon redemption. Can be a single address or an array | Yes |
amountIn | Amount of shares/tokens to redeem in wei (with full decimals) | Yes |
primaryAddress | Address of the contract to interact with | Yes |
receiver | Address to receive the output tokens if not the caller | No |
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)
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Array of addresses of tokens to deposit (usually 2 tokens) | Yes |
tokenOut | Address of the position NFT to receive | Yes |
amountIn | Array of amounts to deposit in wei (with full decimals). Must match the length of tokenIn array | Yes |
ticks | Array containing lower and upper tick bounds defining the price range | Yes |
poolFee | Pool fee tier in basis points (e.g., 3000 for 0.3%) | Yes |
receiver | Address to receive the position NFT if not the caller | No |
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
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of the position NFT token | Yes |
tokenOut | Array of addresses of tokens to receive | Yes |
liquidity | Amount of liquidity to withdraw | Yes |
tokenId | ID of the position NFT | Yes |
receiver | Address to receive the underlying tokens if not the caller | No |
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
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of the single token to deposit | Yes |
tokenOut | Address of the token to receive (usually a receipt or share token) | No |
amountIn | Amount of tokenIn to deposit in wei (with full decimals) | Yes |
primaryAddress | Address of the protocol contract to interact with | Yes |
receiver | Address to receive the output tokens if not the caller | No |
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));
Parameter | Description | Required |
---|
tokenIn | Array of addresses of tokens to deposit | Yes |
tokenOut | Address of the LP token or receipt token to receive | No |
amountIn | Array of amounts to deposit in wei (with full decimals). Must match the length of tokenIn array | Yes |
primaryAddress | Address of the pool or protocol contract to interact with | Yes |
receiver | Address to receive the LP tokens if not the caller | No |
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
}
}
Parameter | Description | Required |
---|
tokenIn | Address of token to deposit | Yes |
tokenOut | Address of tokenized position to receive | Yes |
amountIn | Amount of tokenIn to deposit in wei (with full decimals) | Yes |
primaryAddress | Address of the protocol contract to interact with | Yes |
receiver | Address to receive the position tokens if not the caller | No |
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
}
}
Parameter | Description | Required |
---|
tokenIn | Array of addresses of tokens to deposit | Yes |
tokenOut | Address of the tokenized position to receive | Yes |
amountIn | Array of amounts to deposit in wei (with full decimals). Must match the length of tokenIn array | Yes |
primaryAddress | Address of the protocol contract to interact with | Yes |
receiver | Address to receive the position token if not the caller | No |
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));
Parameter | Description | Required |
---|
tokenIn | Address of the single token to deposit | Yes |
tokenOut | Array of addresses of tokens to receive | Yes |
amountIn | Amount of tokenIn to deposit in wei (with full decimals) | Yes |
primaryAddress | Address of the protocol contract to interact with | Yes |
receiver | Address to receive the output tokens if not the caller | No |
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
},
},
],
);
Parameter | Description | Required |
---|
collateral | Address of the token used as collateral. Can be an array for multiple collateral tokens | Yes |
tokenOut | Address of the token to borrow | Yes |
amountOut | Amount to borrow in wei (with full decimals) | Yes |
primaryAddress | Address of the lending pool contract | Yes |
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",
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of token to repay | Yes |
amountIn | Amount to repay in wei (with full decimals) | Yes |
primaryAddress | Address of the lending pool contract | Yes |
onBehalfOf | Address to repay debt for | Yes |
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
},
},
],
);
Parameter | Description | Required |
---|
token | Address of token to harvest rewards for | Yes |
primaryAddress | Address 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)
},
},
],
);
Parameter | Description | Required |
---|
token | Address of the token to approve | Yes |
spender | Address of the spender (protocol or router) | Yes |
amount | Amount 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
},
},
],
);
Parameter | Description | Required |
---|
token | Address of the token to transfer | Yes |
receiver | Address of the recipient | Yes |
amount | Amount to transfer in wei (with full decimals) | Yes |
id | Token ID for ERC721 or ERC1155 tokens | No |
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)
},
},
],
);
Parameter | Description | Required |
---|
token | Address of the token to transfer | Yes |
sender | Address of the sender | Yes |
receiver | Address of the recipient | Yes |
amount | Amount to transfer in wei (with full decimals) | Yes |
id | Token ID for ERC721 or ERC1155 tokens | No |
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
},
},
],
);
Parameter | Description | Required |
---|
token | Address of the token to transfer. Can be an array for multiple tokens | Yes |
amount | Amount to transfer in wei (with full decimals). Can be an array for multiple tokens | Yes |
sender | Address of the sender | Yes |
receiver | Address of the recipient | Yes |
nonce | Nonce value to prevent signature replay | Yes |
deadline | Timestamp after which the signature is invalid | Yes |
signature | The EIP-2612 permit signature | Yes |
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,
},
},
],
},
},
],
);
Parameter | Description | Required |
---|
primaryAddress | Source bridge pool address | Yes |
destinationChainId | Target blockchain network ID | Yes |
tokenIn | Token address to bridge from source chain | Yes |
amountIn | Amount to bridge (with full decimals) or a reference to a previous action’s output | Yes |
receiver | Address to receive bridged tokens on destination chain | Yes |
callback | Array 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
},
},
],
);
Parameter | Description | Required |
---|
token | Address of the token to check balance | Yes |
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
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Address of the token to split | Yes |
tokenOut | Array of token addresses for the split outputs | Yes |
amountIn | Amount to split in wei (with full decimals) | Yes |
receiver | Address to receive the split tokens | No |
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",
},
},
],
);
Parameter | Description | Required |
---|
tokenIn | Array of input token addresses | Yes |
tokenOut | Address of the output token | Yes |
amountIn | Array of amounts to merge (must be in the same denomination) | Yes |
receiver | Address to receive the merged tokens | No |
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)
],
},
},
],
);
Parameter | Description | Required |
---|
address | Address of the contract to call | Yes |
method | Name of the method to call | Yes |
abi | ABI signature of the method | Yes |
args | Array of arguments to pass to the method | Yes |
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",
},
},
],
);
Parameter | Description | Required |
---|
token | Token address to apply the fee to | Yes |
amount | Amount to apply the fee to (with full decimals) or a return value from a previous action | Yes |
bps | Fee percentage in basis points (1 bps = 0.01%, 100 bps = 1%) | Yes |
receiver | Address to receive the fee | Yes |
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
.