Bridge Kit

A strongly-typed SDK for seamless cross-chain stablecoin bridging
Making cross-chain stablecoin (USDC, and soon more tokens) transfers as simple as a single function call
Table of Contents
Overview
The Stablecoin Kit ecosystem is Circleβs open-source effort to streamline stablecoin development with SDKs that are easy to use correctly and hard to misuse. Kits are cross-framework (viem, ethers, @solana/web3) and integrate cleanly into any stack. Theyβre opinionated with sensible defaults, but offer escape hatches for full control. A pluggable architecture makes implementation flexible, and all kits are interoperable, so they can be composed to suit a wide range of use cases.
The Bridge Kit enables cross-chain stablecoin transfers via a type-safe, developer-friendly interface with robust runtime validation. The Kit can have any bridging provider plugged in, by implementing your own BridgingProvider, but comes by default with full CCTPv2 support
Why Bridge Kit?
- π Bridge-first design: All abstractions revolve around source β destination chain pairs
- β‘ Zero-config defaults: Built-in reliable RPC endpoints - start building right away
- π§ Bring your own infrastructure: Seamlessly integrate with your existing setup when needed
- π Production-ready security: Leverages Circle's CCTPv2 with deterministic quotes and finality tracking
- π Developer experience: Complete TypeScript support, comprehensive validation, and instant connectivity
- π Cross-chain bridging: The Bridge Kit supports 34 chains with 544 total bridge routes through Circle's CCTPv2
- Mainnet (17 chains): Arbitrum, Avalanche, Base, Codex, Ethereum, HyperEVM, Ink, Linea, OP Mainnet, Plume, Polygon PoS, Sei, Solana, Sonic, Unichain, World Chain, XDC
- Testnet (17 chains): Arbitrum Sepolia, Avalanche Fuji, Base Sepolia, Codex Testnet, Ethereum Sepolia, HyperEVM Testnet, Ink Testnet, Linea Sepolia, OP Sepolia, Plume Testnet, Polygon PoS Amoy, Sei Testnet, Solana Devnet, Sonic Testnet, Unichain Sepolia, World Chain Sepolia, XDC Apothem
- π― Flexible adapters: Supporting EVM (Viem, Ethers) and Solana (@solana/web3)
- βοΈ Configurable bridge speeds: FAST/SLOW options with fee optimization
- π‘ Real-time event monitoring: Track progress throughout the transfer lifecycle
- π‘οΈ Robust error handling: Graceful partial success recovery
- βοΈ Pre-flight validation: Verify transfers with cost estimation before execution
Architecture Flow
The Bridge Kit follows a three-layer architecture designed for flexibility and type safety:
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Bridge Kit ββββββ Provider ββββββ Adapter β
β (Orchestrator) β β (Protocol) β β (Blockchain) β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
- Adapter: Handles blockchain-specific operations (wallets, transactions, gas) and enables you to use whatever framework you're comfortable with (viem, ethers, @solana/web3, and more coming soon)
- Provider: Implements bridging protocols (currently CCTPv2)
- BridgeKit: Orchestrates adapters and providers with auto-routing and validation
This separation ensures that each component has a single responsibility while maintaining seamless integration across the entire cross-chain bridging lifecycle.
Installation
npm install @circle-fin/bridge-kit
yarn add @circle-fin/bridge-kit
Adapters
Choose the appropriate adapter for your target chains:
npm install @circle-fin/adapter-viem-v2 viem
yarn add @circle-fin/adapter-viem-v2 viem
npm install @circle-fin/adapter-ethers-v6
yarn add @circle-fin/adapter-ethers-v6
npm install @circle-fin/adapter-solana @solana/web3.js @solana/spl-token
yarn add @circle-fin/adapter-solana @solana/web3.js @solana/spl-token
Quick Start
π Easiest Setup: Single Adapter, Multiple Chains
Best for: Getting started quickly, simple transfers using one wallet across chains
The factory methods make it incredibly easy to get started with built-in reliable RPC endpoints. No need to research providers or configure endpoints - just start building! Create one adapter and use it across different chains!
import { BridgeKit } from '@circle-fin/bridge-kit'
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
const kit = new BridgeKit()
const adapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
})
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '10.50',
})
β¨ Key Feature: All supported chains include reliable default RPC endpoints.
π― Send to Different Address
Best for: Sending funds to someone else's wallet, custodial services
Use BridgeDestinationWithAddress when the recipient is different from your adapter's address:
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: {
adapter,
chain: 'Base',
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
},
amount: '10.50',
})
const baseAdapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
})
const resultWithDifferentAdapter = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: {
adapter: baseAdapter,
chain: 'Base',
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
},
amount: '10.50',
})
π Production Setup: Custom RPC Providers
Best for: Production applications, better reliability, custom configuration
import { createPublicClient, http } from 'viem'
const adapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
getPublicClient: ({ chain }) =>
createPublicClient({
chain,
transport: http(
`https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
{
retryCount: 3,
timeout: 10000,
},
),
}),
})
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '10.50',
})
π Browser/Wallet Provider Support
Best for: Browser applications, wallet integrations, user-controlled transactions
import { createAdapterFromProvider } from '@circle-fin/adapter-viem-v2'
const adapter = await createAdapterFromProvider({
provider: window.ethereum,
})
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '10.50',
})
π§ Advanced Setup: Full Control
Best for: Advanced users, custom client configuration, specific RPC requirements
import { BridgeKit } from '@circle-fin/bridge-kit'
import { Ethereum, Base } from '@circle-fin/bridge-kit/chains'
import { ViemAdapter } from '@circle-fin/adapter-viem-v2'
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.PRIVATE_KEY as string)
const rpcUrls = {
[Ethereum.id]: 'https://eth-mainnet.alchemyapi.io/v2/YOUR_KEY',
[Base.id]: 'https://base-mainnet.g.alchemy.com/v2/YOUR_KEY',
}
const adapter = new ViemAdapter(
{
getPublicClient: ({ chain }) =>
createPublicClient({
chain,
transport: http(rpcUrls[chain.id]),
}),
getWalletClient: ({ chain }) =>
createWalletClient({
account,
chain,
transport: http(rpcUrls[chain.id]),
}),
},
{
addressContext: 'user-controlled',
supportedChains: [Ethereum, Base],
},
)
const kit = new BridgeKit()
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '10.50',
})
π Cost Estimation
Best for: Showing users fees upfront, budget planning
const estimate = await kit.estimate({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '10.50',
})
console.log('Estimated fees:', estimate.fees)
console.log('Estimated gas:', estimate.gasFees)
Configuration
Bridge Configuration Types
The Bridge Kit supports different configuration patterns to match your use case:
1. AdapterContext - Your Transfer Endpoint
const adapter = createAdapterFromPrivateKey({...})
const adapterContext = { adapter, chain: 'Ethereum' }
2. BridgeDestination - Where Funds Go
const destination = { adapter, chain: 'Base' }
const destination = {
adapter,
chain: 'Base',
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
}
3. BridgeConfig - Transfer Settings
const config = { transferSpeed: 'FAST' }
Bridge Speed Configuration
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '100.0',
config: { transferSpeed: 'FAST' },
})
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '100.0',
config: { transferSpeed: 'SLOW' },
})
Error Handling
The kit uses a thoughtful error handling approach:
- Hard errors (thrown): Validation, configuration, and authentication errors
- Soft errors (returned): Recoverable issues like insufficient balance or network errors
import { BridgeKit } from '@circle-fin/bridge-kit'
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
const kit = new BridgeKit()
const adapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
})
const params = {
from: { adapter, chain: 'Ethereum' },
to: { adapter, chain: 'Base' },
amount: '100.0',
}
const result = await kit.bridge(params)
if (result.state === 'success') {
console.log('Bridge successful!')
} else {
console.log(
'Successful steps:',
result.steps.filter((s) => s.state === 'success'),
)
}
Retrying Failed Transfers
Use BridgeKit.retry to resume failed or incomplete bridge operations when the failure is actionable (e.g., transient RPC issues, dropped transactions, or a failed step in a multi-step flow). The kit delegates retry to the original provider (CCTPv2 supports actionable retries) and continues from the appropriate step.
Method signature
retry<
TFromAdapterCapabilities extends AdapterCapabilities,
TToAdapterCapabilities extends AdapterCapabilities
>(
result: BridgeResult,
context: RetryContext<TFromAdapterCapabilities, TToAdapterCapabilities>
): Promise<BridgeResult>
Basic usage (EVM β EVM)
import { BridgeKit } from '@circle-fin/bridge-kit'
import { createAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
const kit = new BridgeKit()
const adapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
})
const result = await kit.bridge({
from: { adapter, chain: 'Ethereum_Sepolia' },
to: { adapter, chain: 'Base_Sepolia' },
amount: '1',
})
if (result.state === 'error') {
try {
const retryResult = await kit.retry(result, { from: adapter, to: adapter })
console.log('Retry state:', retryResult.state)
} catch (error) {
console.error('Retry failed:', error)
}
}
When to retry vs manual intervention
- Retry: transient network/RPC errors, gas repricing/dropped txs, step failure with progress recorded.
- Manual: insufficient funds, incorrect recipient, unsupported route, or errors indicating non-actionable state.
Limitations
- Only actionable failures can be retried; some failures require user action first.
- Source and destination chains must still be supported by the provider (CCTPv2).
- Provide valid adapters for both
from and to contexts.
Performance and best practices
- Use exponential backoff on transient failures; avoid rapid replay.
- Reprice gas sensibly on congested networks.
- Persist
result.steps and tx hashes to aid observability and support.
Troubleshooting
- "Retry not supported for this result, requires user action": fix balances/addresses/attestation issues and try again.
- "Provider not found": ensure the same provider (e.g., CCTPv2) is present in
BridgeKit configuration.
See a runnable example at examples/basic-usdc-transfer/src/retry.ts (script: yarn start:retry).
API Reference
Core Methods
kit.bridge(params) - Execute cross-chain bridge operation
kit.estimate(params) - Get cost estimates before bridging
kit.retry(result, context) - Resume actionable failed/partial transfers
kit.supportsRoute(source, destination, token) - Check route support
kit.on(event, handler) - Listen to bridge events
kit.off(event, handler) - Removes the listener from bridge events
Bridge Parameters
interface BridgeParams {
from: AdapterContext
to: BridgeDestination
amount: string
token?: 'USDC'
config?: BridgeConfig
}
type AdapterContext = {
adapter: Adapter
chain: ChainIdentifier
address?: string
}
type BridgeDestination =
| AdapterContext
| {
adapter: Adapter
chain: ChainIdentifier
recipientAddress: string
}
Development
Building
nx build @circle-fin/bridge-kit
Testing
nx test @circle-fin/bridge-kit
Local Development
yarn install
yarn build
nx build @circle-fin/bridge-kit
nx test @circle-fin/bridge-kit
License
This project is licensed under the Apache 2.0 License. Contact support for details.
Ready to start bridging?
Join Discord
Built with β€οΈ by Circle