For the complete documentation index, see llms.txt. This page is also available as markdown.

Quickstart

Installation

npm i @zerodev/smart-routing-address
yarn add @zerodev/smart-routing-address
pnpm i @zerodev/smart-routing-address
bun add @zerodev/smart-routing-address

Create a project

Project ID required

Create a project in the ZeroDev dashboard and copy its project ID. You'll pass it as projectId below.

Usage

Smart Routing Address has a beautifully simple API: just createSmartRoutingAddress and then send funds to it. That's really it.

We recommend that you take a look at our code example (even better if you try running it) as you follow along the docs.

Creating a smart routing address

In the following example, we are going to create a smart routing address that, when receiving funds on any chain, will deliver the funds to a specific address on Arbitrum. This is helpful when, for instance, you want to create a deposit address for your user, so that they can send funds to the address on any chain (possibly from a CEX), and then they will receive funds in their wallet on the chain that your app runs on.

First import some functions and constants:

import {
  createSmartRoutingAddress,
  SMART_ROUTING_ADDRESS_V1_0_0,
} from "@zerodev/smart-routing-address";
import { arbitrum, base } from "viem/chains";

Then create a smart routing address:

// Replace with your own address
const owner = "0xddED85de258cC7a33A61BC6215DD766E87a97070";

const { smartRoutingAddress, estimatedFees } = await createSmartRoutingAddress({
  owner,
  projectId: "<YOUR_PROJECT_ID>",
  destChain: arbitrum,
  recipient: owner, // funds land here on Arbitrum
  // Source tokens (any ERC20 and ETH on Base)
  srcTokens: [
    { tokenType: "ERC20", chain: base },
    { tokenType: "NATIVE", chain: base },
  ],
  slippage: 5000,
  version: SMART_ROUTING_ADDRESS_V1_0_0,
});

The options are:

  • owner is an address that is authorized to recover funds from the smart routing address, in case the smart routing address fails to deliver the funds for whatever reason. Typically you would set this to your user's EOA wallet, but you could also set it to your own address if you want to recover funds for users.

  • projectId is your ZeroDev project ID, which you can find on the dashboard.

  • destChain is the chain on which the funds are delivered. This is presumably the chain that your app runs on.

  • recipient is the address that receives the funds on destChain. It is often the same as owner, but it doesn't have to be.

  • actions is optional in this mode. To run custom logic on arrival, pass calls (see Executing calls on arrival below).

  • srcTokens is a list of tokens that the smart routing address should be able to receive. Only tokens listed in srcTokens will be routed to the destination. The other tokens sent to the address will have to be manually recovered by the owner.

  • slippage is the maximum slippage that the user can expect. slippage is an integer, where 1 is equal to 0.01% (so 100 would mean 1% slippage).

  • version pins your integration to a known smart routing address version. Always pass the latest constant exported by the SDK.

The return value also includes estimatedFees, the estimated fee for each source token deposit.

Once you have created a smart routing address, you can send tokens to it on any of the chains specified in srcTokens, and the funds will be delivered to recipient on the destChain. It's really that simple.

Executing calls on arrival

If you need to do something with the funds when they arrive (for example deposit into a vault), pass an actions map instead of recipient. Each entry maps a received token type to the calls that run on the destination chain. Build calls with createCall, using FLEX placeholders for the token address and amount, which aren't known until a deposit lands.

import {
  createSmartRoutingAddress,
  createCall,
  FLEX,
  SMART_ROUTING_ADDRESS_V1_0_0,
} from "@zerodev/smart-routing-address";
import { erc20Abi } from "viem";
import { arbitrum, base } from "viem/chains";

const owner = "0xddED85de258cC7a33A61BC6215DD766E87a97070";

// Transfer whatever ERC20 arrives, in whatever amount, to `owner`
const erc20Call = createCall({
  target: FLEX.TOKEN_ADDRESS,
  value: 0n,
  abi: erc20Abi,
  functionName: "transfer",
  args: [owner, FLEX.AMOUNT],
});

// Send whatever native amount arrives to `owner`
const nativeCall = createCall({
  target: owner,
  value: FLEX.NATIVE_AMOUNT,
});

const { smartRoutingAddress, estimatedFees } = await createSmartRoutingAddress({
  owner,
  projectId: "<YOUR_PROJECT_ID>",
  destChain: arbitrum,
  actions: {
    USDC: { action: [erc20Call] },
    WRAPPED_NATIVE: { action: [erc20Call] },
    NATIVE: { action: [nativeCall] },
  },
  srcTokens: [
    { tokenType: "ERC20", chain: base },
    { tokenType: "NATIVE", chain: base },
  ],
  slippage: 5000,
  version: SMART_ROUTING_ADDRESS_V1_0_0,
});

See Deposit Modes for a full comparison of the two modes.

On this page