Quickstart
Installation
npm i @zerodev/smart-routing-addressyarn add @zerodev/smart-routing-addresspnpm i @zerodev/smart-routing-addressbun add @zerodev/smart-routing-addressCreate 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:
-
owneris 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. -
projectIdis your ZeroDev project ID, which you can find on the dashboard. -
destChainis the chain on which the funds are delivered. This is presumably the chain that your app runs on. -
recipientis the address that receives the funds ondestChain. It is often the same asowner, but it doesn't have to be. -
actionsis optional in this mode. To run custom logic on arrival, pass calls (see Executing calls on arrival below). -
srcTokensis a list of tokens that the smart routing address should be able to receive. Only tokens listed insrcTokenswill be routed to the destination. The other tokens sent to the address will have to be manually recovered by theowner. -
slippageis the maximum slippage that the user can expect.slippageis an integer, where 1 is equal to 0.01% (so 100 would mean 1% slippage). -
versionpins 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.