Defines the transfer details: origin, destination, amount, sender/recipient addresses, and optional gas drop-off.
constroutes=awaitstable.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 EvmAddressconstroutes=awaitstable.findRoutes({sender:newEvmAddress("0x..."),// or just a stringamount:usdc(0.5),// or string "0.5" or bigint in atomic units...});// Access different route optionsconsole.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 objects
fastest: reference to the fastest route
cheapest: reference to the cheapest route
Each route includes:
intent: original intent used to compute the route
estimatedDuration: number (in seconds)
estimatedTotalCost: cost in USD
fees: detailed fee breakdown
corridor: route type (e.g., "v1", "v2Direct", "avaxHop")
progress: emits high-level transfer lifecycle events
workflow: async generator for manual execution flows
Example return
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.
An object describing the full lifecycle of the transfer:
transferHash: hash of the transaction that originated the transfer on the source chain
redeemHash: hash of the transaction that redeemed the transfer on the target chain
transactions: 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)
Example return
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.
Lifecycle Events
1
message-signed
The user signed a message to authorize part of the transfer (e.g., permit or other message types).
Example
2
approval-sent
The user signed and sent an approval transaction.
Example
3
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).
4
transfer-sent
The user signed and sent the transfer transaction.
Example
5
transfer-confirmed
Circle attestation service confirmed the transfer (v1 or v2 format).
Example
transfer-confirmed may differ between CCTPv1 and CCTPv2.
6
hop-redeemed (If using Avax Hop)
The first transfer was redeemed on avalanche.
7
hop-confirmed (If using Avax Hop)
The second transfer was confirmed by circle
8
transfer-redeemed
The transfer was redeemed on the destination chain.
Example
9
step-completed
Special event that fires on every step. The payload includes name and data.
Example
route.transactionListener
These events monitor wallet transactions, specifically those the user signs and pays for.
Lifecycle Events
1
transaction-sent
The transaction was sent to the blockchain.
Example
2
transaction-included
The transaction was included in a block.
Example
Error Handling
Handle transfer errors using the progress event system:
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.
Useful for advanced integrations that require granular control over the execution flow, including special handling of permit transactions.
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;
}
});
for await (const tx of route.workflow) {
// tx is the next transaction to sign and send
await tx.signAndSend();
}