Easily Integrate Deep Stablecoin Liquidity in Your App with the Eco Routes SDK
A quick and easy tutorial helping you integrate Eco Routes into your on-chain app in just 30 minutes

Eco Routes enables apps and blockchains to access permissionless, cross-chain stablecoin liquidity. It uses an intent-based framework to simplify complex on-chain actions into one simple transfer. Routes are flexible and configurable, allowing developers to prioritize speed, cost, and security according to their preferences. Currently, Native and Hyperlane Routes are live, enabling fast or trustless stablecoin transfers from any rollup settling on Ethereum (L2 or L3).
Here is a quick and easy tutorial outlining how to integrate Eco Routes using the Routes SDK, simplifying the process of intent creation, order quoting, and order fulfillment.
This guide uses wagmi and viem.
Steps:
- Create the intent
- Request quotes for an intent and select one
- Apply the quote to the intent
- Approve and submit the intent on-chain
- Wait for fulfillment
Step 1: Create the intent
To initiate a cross-chain transfer, you first need to create an intent.
import { RoutesService } from "@eco-foundation/routes-sdk";
const address = "0x1234567890123456789012345678901234567890";
const originChainID = 10;
const spendingToken = RoutesService.getStableAddress(originChainID, "USDC");
const spendingTokenLimit = BigInt(10000000); // 10 USDC
const destinationChainID = 8453;
const receivingToken = RoutesService.getStableAddress(destinationChainID, "USDC");
const amount = BigInt(1000000); // 1 USDC
const routesService = new RoutesService();
const intent = routesService.createSimpleIntent({
creator: address,
originChainID,
spendingToken,
spendingTokenLimit,
destinationChainID,
receivingToken,
amount,
});
The example above uses sample data, but in practice, you should generate a new intent whenever the user changes an input value, and all required fields are populated.
Step 2: Request quotes for an intent, and select one:
Once you have a valid intent, request quotes for it. This is an asynchronous operation that should be triggered whenever the intent updates.
import { OpenQuotingClient, selectCheapestQuote } from "@eco-foundation/routes-sdk";
const openQuotingClient = new OpenQuotingClient({ dAppID: "my-dapp" });
try {
const quotes = await openQuotingClient.requestQuotesForIntent(intent);
}
catch (error) {
console.error("Quotes not available", error);
}
Ensure you handle cases where no quotes are available by logging an error state and displaying an appropriate message for your end user.
Next, select a quote from the available options. If you want the most cost-effective option, use the selectCheapestQuote function provided in the SDK.
import { selectCheapestQuote } from "@eco-foundation/routes-sdk";
const selectedQuote = selectCheapestQuote(quotes);
You can also implement a custom selection strategy based on your needs.
Step 3: Apply the quote to the intent
The Eco Protocol supports actions beyond simple transfers, so the quoting system calculates the exact amount a solver needs from you on the origin chain to fulfill the destination action.
For this reason, it’s best to create an intent specifying the amount desired for the destination chain. Once you receive a quote, adjust the origin chain amount to include the fee.
If your bridge implementation requires specifying only the amount to send, see Step 3b.
Step 3a: Apply the quote using the SDK
Simply call the applyQuoteToIntent method.
const intentWithQuote = routesService.applyQuoteToIntent({
intent,
quote: selectedQuote
});
At this point, your intent is ready to be published!
Step 3b: Apply the quote to the intent reversely (simple stable intents only)
For simple stable intents that require specifying the send amount rather than the receive amount, extract the fee and destination amount from the selected quote:
const fee = BigInt(selectedQuote.quoteData.tokens[0]!.amount) - amount;
const destinationAmount = amount - fee;
Then, modify the intent as follows:
- Overwrite the intent’s reward amount with the user’s intended send amount.
intent.reward.tokens[0]!.amount = amount;
- Set the route tokens amount to the destination amount.
intent.route.tokens[0]!.amount = destinationAmount;
- Generate new calldata for the simple stable send with the destination amount.
import { encodeFunctionData, erc20Abi } from "viem";
intent.route.calls[0]!.data = encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [address, destinationAmount],
});
const intentWithQuote = intent;
Your intent is now ready to be published!
Step 4: Approve and submit the intent on-chain
Before publishing, grant approval for the IntentSource contract to spend the required tokens on the origin chain.
import { writeContract, waitForTransactionReceipt } from "@wagmi/core";
import { EcoProtocolAddresses } from "@eco-foundation/routes-ts";
const intentSourceContract = EcoProtocolAddresses[routesService.getEcoChainId(originChainID)].IntentSource;
try {
await Promise.all(intentWithQuote.reward.tokens.map(async ({ token, amount }) => {
const approveTxHash = await writeContract(wagmiConfig, {
abi: erc20Abi,
address: token,
functionName: "approve",
args: [intentSourceContract, amount],
chainId: originChainID,
});
await waitForTransactionReceipt(wagmiConfig, {
hash: approveTxHash,
chainId: originChainID,
});
}));
}
catch (error) {
console.error(error);
}
Next, publish the intent by calling publishAndFund.
import { IntentSourceAbi } from "@eco-foundation/routes-ts";
try {
const publishTxHash = await writeContract(wagmiConfig, {
abi: IntentSourceAbi,
address: intentSourceContract,
functionName: "publishAndFund",
args: [intentWithQuote, false],
chainId: originChainID,
});
const publishReceipt = await waitForTransactionReceipt(wagmiConfig, {
hash: publishTxHash,
chainId: originChainID,
});
}
catch (error) {
console.error(error);
}
Step 5: Wait for fulfillment
Once published, you'll need to track when the funds arrive at their destination.
First, extract the intent hash from the event emitted by the publishAndFund transaction.
import { parseEventLogs } from "viem";
const logs = parseEventLogs({
abi: IntentSourceAbi,
logs: publishReceipt.logs,
});
const intentCreatedEvent = logs.find(
(log) => log.eventName === "IntentCreated",
);
const intentHash = intentCreatedEvent!.args.hash;
Then, use the intent hash to listen for a Fulfillment event from the Inbox contract on the destination chain.
import { InboxAbi } from "@eco-foundation/routes-ts";
import { getBlockNumber, watchContractEvent } from "@wagmi/core";
import { Hex } from "viem";
const blockNumber = await getBlockNumber(wagmiConfig, {
chainId: destinationChainID
});
const fulfillmentTxHash = await new Promise<Hex>((resolve, reject) => {
const unwatch = watchContractEvent(wagmiConfig, {
fromBlock: blockNumber - BigInt(10),
chainId: destinationChainID,
abi: InboxAbi,
eventName: "Fulfillment",
address: intentWithQuote.route.inbox,
args: {
_hash: intentHash
},
onLogs(logs) {
if (logs && logs.length > 0) {
const fulfillmentTxHash = logs[0]!.transactionHash;
unwatch();
resolve(fulfillmentTxHash);
}
},
onError(error) {
unwatch();
reject(error);
}
});
});
Note: Fulfillments happen quickly—by the time you extract the intent hash, the event may have already been emitted. To avoid missing it, check a few blocks in the past.
Once the fulfillment event is detected, the user’s funds will arrive in their wallet!
About Eco
Eco enables any onchain action to be a simple, one-click stablesend. With Eco, apps can easily accept anyone’s preferred stablecoin, regardless of the network — unlocking stablecoin liquidity from any connected chain and giving users the simplest onchain experience. To make this possible, the Eco Protocol brings together Routes, Accounts, and Crowd Liquidity (coming soon) to give app developers the ultimate flexibility while prioritizing speed, cost, and security.
Website | Eco Docs | Twitter | LinkedIn | Discord | Forum
About Eco Inc.
Eco Inc. is a blockchain company building software that maximizes money’s value. The company is a founding contributor to the Eco Protocol and the builder of Bend. We expect better from our money, and we want you to as well. That’s what drives us every day.