Methods
Find Routes
findRoutes(intent)
Returns available routes to fulfill the intent.
Parameters
intent
Defines the transfer details: origin, destination, amount, sender/recipient addresses, and optional gas drop-off.
const routes = await stable.findRoutes({
sourceChain: string,
targetChain: string,
sender: string | EvmAddress,
amount: string | bigint | Amount,
recipient: string, // 0x-prefixed address
gasDropoffDesired?: bigint, // Optional. Native gas token amount to include on the destination chain
paymentToken?: "usdc" | "native",
usePermit?: true, // Optional. Defaults to true
});
// You can also use utility classes like Amount and EvmAddress
const routes = await stable.findRoutes({
sender: new EvmAddress("0x..."), // or just a string
amount: usdc(0.5), // or string "0.5" or bigint in atomic units
...
});
// Access different route options
console.log("Fastest route:", routes.fastest);
console.log("Cheapest route:", routes.cheapest);
console.log("All routes:", routes.all);
Returns
A routes
object containing:
all
: list of route objectsfastest
: reference to the fastest routecheapest
: reference to the cheapest route
Each route includes:
intent
: original intent used to compute the routeestimatedDuration
: number (in seconds)estimatedTotalCost
: cost in USDfees
: detailed fee breakdowncorridor
: route type (e.g.,"v1"
,"v2Direct"
,"avaxHop"
)steps
: transaction actions (e.g.,sign-and-send-transaction
,sign-message
,sign-permit
)requiresMessageSignature
: whether the route usespermit
(vsapproval
)transactionListener
: emits blockchain tx-level eventsprogress
: emits high-level transfer lifecycle eventsworkflow
: async generator for manual execution flows
Authorization Methods
Each route either uses:
Approval: Requires an on-chain approval transaction. Suitable for users who trust the CCTPR contract and interact frequently — often done outside the SDK for better gas optimization.
Permit: Requires a signed message. Preferable for users who interact less frequently or want to minimize trust assumptions. Slightly more secure for one-off interactions.
You can detect this via:
route.requiresMessageSignature // true = uses permit
Gasless Transfers
Allow users to pay transaction fees using USDC instead of native tokens like ETH or MATIC. No need to hold gas tokens to complete transfers.
const routes = await stable.findRoutes({
sourceChain: "Ethereum",
targetChain: "Polygon",
amount: "100",
sender: account.address,
recipient: account.address,
paymentToken: "usdc", // Automatically includes gasless routes
});
// Gasless routes handle all gas payments with USDC
const gaslessRoute = routes.all.find(route =>
route.steps.some(step => step.type === "gasless-transfer")
);
Check if sender has enough funds
checkHasEnoughFunds(route)
Checks whether the sender has enough USDC/native tokens to cover all required fees for the given route.
Parameters
route
One of the objects returned from findRoutes
.
Returns
Boolean
: true if sufficient funds, otherwise false.
Execute route
executeRoute(route)
Executes the given route. Automatically handles pre-approvals or permits.
Parameters
route
One of the objects returned from findRoutes
.
Returns
An object describing the full lifecycle of the transfer:
transferHash
: hash of the transaction that originated the transfer on the source chainredeemHash
: hash of the transaction that redeemed the transfer on the target chaintransactions
: array of transaction hashes signed and paid by the user (e.g. approval, transfer)attestations
: Circle attestations of the transfer (can include two if using Avax Hop)redeems
: redemption transaction data (can include two if using Avax Hop)
executeRoute() resolves after the transfer is redeemed on the destination chain. To monitor transfer progress, use route.progress. To observe signed blockchain transactions, use route.transactionListener.
Transaction tracking
route.progress
route.progress
emits events representing each step in the lifecycle of the transfer.
route.progress.on("transfer-initiated", (data) => {
console.log("Transfer started:", data);
});
route.progress.on("transfer-confirmed", (data) => {
console.log("Transfer confirmed on source chain:", data);
});
Lifecycle Events
message-signed
The user signed a message to authorize part of the transfer (e.g., permit or other message types).
approval-sent
The user signed and sent an approval transaction.
transfer-initiated
The transfer process has started. This event signals that the SDK is ready to submit the transfer transaction. Useful for UI state changes (e.g., loading spinners).
transfer-sent
The user signed and sent the transfer transaction.
transfer-confirmed
Circle attestation service confirmed the transfer (v1 or v2 format).
transfer-confirmed
may differ between CCTPv1 and CCTPv2.
hop-redeemed
(If using Avax Hop)
The first transfer was redeemed on avalanche.
hop-confirmed
(If using Avax Hop)
The second transfer was confirmed by circle
transfer-redeemed
The transfer was redeemed on the destination chain.
step-completed
Special event that fires on every step. The payload includes name
and data
.
route.transactionListener
These events monitor wallet transactions, specifically those the user signs and pays for.
route.transactionListener.on("transaction-sent", (txData) => {
console.log("Transaction sent:", txData.hash);
});
route.transactionListener.on("transaction-included", (receipt) => {
console.log("Transaction included in block:", receipt.blockNumber);
});
Lifecycle Events
transaction-sent
The transaction was sent to the blockchain.
transaction-included
The transaction was included in a block.
Error Handling
Handle transfer errors using the progress event system:
route.progress.on("error", (errorData) => {
switch (errorData.type) {
case "transfer-failed":
// Transaction failed, tokens remained in source account
console.error("Transfer transaction failed");
// errorData.details is undefined for transfer-failed
break;
case "attestation-failed":
// Circle's attestation service issues
console.error("Circle attestation failed for transaction:", errorData.details.txHash);
// Retry logic could be implemented here
break;
case "receive-failed":
// Destination chain receive transaction failed
console.error("Destination receive failed for transaction:", errorData.details.txHash);
// Manual intervention may be required
break;
}
});
Advanced: Custom Step Execution
Each route exposes an async generator via route.workflow
. This allows advanced developers to handle signing and transaction submission step-by-step.
for await (const tx of route.workflow) {
// tx is the next transaction to sign and send
await tx.signAndSend();
}
Useful for advanced integrations that require granular control over the execution flow, including special handling of permit
transactions.
Last updated
Was this helpful?