Skip to main content
This instruction type enables straightforward token swaps (same-chain or cross-chain). You specify source and destination tokens, and the system automatically finds the optimal route through bridge aggregators and swap providers.

How It Works

The intent-simple flow:
  1. Analyzes swap parameters - Source/destination tokens and chains
  2. Finds optimal route - Leverages LiFi, GlueX, Across, and other providers
  3. Handles complexity - Manages bridging, swapping, and multi-step routes
  4. Returns route details - Provides expected output and routing information

Parameters

When using /instructions/intent-simple in your composeFlows array:
ParameterTypeRequiredDescription
srcTokenstringYesSource token address (checksummed)
dstTokenstringYesDestination token address (checksummed)
srcChainIdnumberYesSource chain ID
dstChainIdnumberYesDestination chain ID
amountstringYesAmount to swap (in wei/smallest unit)
slippagenumberYesSlippage tolerance (0-1, e.g., 0.01 = 1%)
allowSwapProvidersstringNoComma-separated allowed swap providers
denySwapProvidersstringNoComma-separated denied swap providers
allowBridgeProvidersstringNoComma-separated allowed bridge providers
denyBridgeProvidersstringNoComma-separated denied bridge providers

Complete Workflow Examples

  • EOA Mode
  • Smart Account
  • Same-Chain Swap
Cross-chain swap with withdrawal
import { createWalletClient, http, parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const account = privateKeyToAccount('0x...');
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http()
});

// Step 1: Build quote request with intent-simple in composeFlows
const quoteRequest = {
  mode: 'eoa',
  ownerAddress: account.address,
  fundingTokens: [{
    tokenAddress: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC on Base
    chainId: 8453,
    amount: parseUnits('100', 6).toString()
  }],
  feeToken: {
    address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
    chainId: 8453
  },
  composeFlows: [
    // Cross-chain swap: USDC (Base) → USDT (OP)
    {
      type: '/instructions/intent-simple',
      data: {
        srcChainId: 8453,
        dstChainId: 10,
        srcToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
        dstToken: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58',
        amount: parseUnits('100', 6).toString(),
        slippage: 0.01,
        denySwapProviders: 'gluex' // Optional: exclude providers
      }
    },
    // Withdraw USDT to EOA (critical for EOA mode)
    {
      type: '/instructions/build',
      data: {
        functionSignature: 'function transfer(address to, uint256 value)',
        args: [
          account.address,
          {
            type: 'runtimeErc20Balance',
            tokenAddress: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58',
            constraints: { gte: '1' }
          }
        ],
        to: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58',
        chainId: 10
      }
    }
  ]
};

// Step 2: Get quote
const quote = await fetch('https://api.biconomy.io/v1/quote', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(quoteRequest)
}).then(r => r.json());

console.log('Quote type:', quote.quoteType); // 'permit' for USDC
console.log('Fee:', quote.fee.amount);

// Check swap details from returnedData
const swapResult = quote.returnedData[0];
console.log('Expected output:', swapResult.outputAmount);
console.log('Min output:', swapResult.minOutputAmount);
console.log('Route:', swapResult.route.summary);

// Then sign and POST to /v1/execute

Returned Data Structure

When you use intent-simple in your quote request, the response includes returnedData with swap details:
{
  "ownerAddress": "0x...",
  "mode": "eoa",
  "fee": {...},
  "quoteType": "permit",
  "quote": {...},
  "payloadToSign": [...],
  "returnedData": [
    {
      "outputAmount": "99950000",
      "minOutputAmount": "98950000",
      "route": {
        "summary": "lifi[uniswapv3] => across[SpokePoolV3]",
        "steps": [
          {
            "type": "swap",
            "protocol": "lifi",
            "sources": ["uniswapv3"],
            "srcToken": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "dstToken": "0x94b008aa00579c1307b0ef2c499ad98a8ce58e58",
            "srcChainId": 8453,
            "dstChainId": 10,
            "inputAmount": "100000000",
            "outputAmount": "99950000",
            "minOutputAmount": "98950000"
          }
        ],
        "type": "DIRECT",
        "totalGasFeesUsd": 0.05,
        "totalBridgeFeesUsd": 0.02,
        "estimatedTime": 180
      }
    }
  ]
}

Route Data Fields

FieldTypeDescription
outputAmountstringExpected output amount (in wei)
minOutputAmountstringMinimum output after slippage (in wei)
route.summarystringHuman-readable route description
route.stepsarrayDetailed steps with protocol info
route.typestringRoute strategy (e.g., “DIRECT”, “PIVOT_USDT”)
route.totalGasFeesUsdnumberEstimated gas fees in USD
route.totalBridgeFeesUsdnumberEstimated bridge fees in USD
route.estimatedTimenumberEstimated time in seconds
Each step contains:
FieldDescription
type”swap” or “bridge”
protocolProvider used (e.g., “lifi”, “across”)
sourcesDEXes used (e.g., [“uniswapv3”])
srcToken, dstTokenToken addresses
srcChainId, dstChainIdChain IDs
inputAmount, outputAmountAmounts for this step

Provider Control

Control which providers are used for routing:
{
  type: '/instructions/intent-simple',
  data: {
    // ... other params
    allowSwapProviders: 'lifi,gluex',        // Only use these for swaps
    denySwapProviders: 'gluex',              // Exclude these from swaps
    allowBridgeProviders: 'across',          // Only use these for bridging
    denyBridgeProviders: 'some-bridge'       // Exclude these from bridging
  }
}
Available Providers:
  • Swap: LiFi, GlueX, and others
  • Bridge: Across, and others

Best Practices

When using EOA mode, funds remain in Nexus after operations. Always add a withdrawal instruction:
{
  type: '/instructions/build',
  data: {
    functionSignature: 'function transfer(address to, uint256 value)',
    args: [
      ownerAddress,
      {
        type: 'runtimeErc20Balance',
        tokenAddress: dstToken,
        constraints: { gte: '1' }
      }
    ],
    to: dstToken,
    chainId: dstChainId
  }
}
Always check the minOutputAmount to ensure acceptable slippage:
const swapResult = quote.returnedData[0];
const outputUi = formatUnits(BigInt(swapResult.outputAmount), 6);
const minOutputUi = formatUnits(BigInt(swapResult.minOutputAmount), 6);

console.log(`Expected: ${outputUi} USDT (min: ${minOutputUi})`);

if (Number(minOutputUi) < acceptableMinimum) {
  throw new Error('Output too low after slippage');
}
Set slippage based on market conditions and token liquidity:
// Stablecoin swaps: low slippage
slippage: 0.001  // 0.1%

// Volatile token swaps: higher slippage
slippage: 0.03   // 3%

// Cross-chain: moderate slippage
slippage: 0.01   // 1%
Check the route summary for unexpected routing:
const route = quote.returnedData[0].route;
console.log('Route:', route.summary);
console.log('Gas fees:', route.totalGasFeesUsd);
console.log('Bridge fees:', route.totalBridgeFeesUsd);
console.log('Estimated time:', route.estimatedTime, 'seconds');

Troubleshooting

If no route is available:
  • Check token addresses are correct and checksummed
  • Verify both tokens are supported on their respective chains
  • Try adjusting provider allow/deny lists
  • Increase slippage tolerance if needed
If minOutputAmount is lower than expected:
  • Check current market prices and liquidity
  • Review the route.steps to see where value is lost
  • Consider splitting large swaps into smaller ones
  • Try different providers using allow/deny parameters
If execution fails:
  • Check sufficient balance in source location (EOA or Nexus)
  • Verify slippage wasn’t exceeded during execution
  • Review transaction on MEE Explorer for specific error