bridge-stablecoin

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Overview

概述

Crosschain Transfer Protocol (CCTP) is Circle's native protocol for burning USDC on one chain and minting it on another. Bridge Kit is a TypeScript SDK that orchestrates the full CCTP lifecycle -- approve, burn, attestation fetch, and mint -- in a single
kit.bridge()
call across EVM chains and Solana. Bridge Kit is the preferred way to integrate CCTP.
跨链转账协议(CCTP)是Circle推出的原生协议,可在一条链上销毁USDC,并在另一条链上铸造USDC。Bridge Kit是一款TypeScript SDK,能够通过单次
kit.bridge()
调用,在EVM链与Solana之间协调完成CCTP全生命周期流程——授权、销毁、获取证明、铸造。Bridge Kit是集成CCTP的首选方式。

Prerequisites / Setup

前置条件 / 配置

Installation

安装

bash
npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2
For Solana support, also install:
bash
npm install @circle-fin/adapter-solana-kit
For Circle Wallets (developer-controlled) support:
bash
npm install @circle-fin/adapter-circle-wallets
bash
npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2
如需支持Solana,还需安装:
bash
npm install @circle-fin/adapter-solana-kit
如需支持Circle钱包(开发者控制):
bash
npm install @circle-fin/adapter-circle-wallets

Environment Variables

环境变量

PRIVATE_KEY=              # EVM wallet private key (hex, 0x-prefixed)
EVM_PRIVATE_KEY=          # EVM private key (when also using Solana)
SOLANA_PRIVATE_KEY=       # Solana wallet private key (base58)
CIRCLE_API_KEY=           # Circle API key (for Circle Wallets adapter)
CIRCLE_ENTITY_SECRET=     # Entity secret (for Circle Wallets adapter)
EVM_WALLET_ADDRESS=       # Developer-controlled EVM wallet address
SOLANA_WALLET_ADDRESS=    # Developer-controlled Solana wallet address
PRIVATE_KEY=              # EVM钱包私钥(十六进制,以0x开头)
EVM_PRIVATE_KEY=          # EVM私钥(同时使用Solana时需配置)
SOLANA_PRIVATE_KEY=       # Solana钱包私钥(base58格式)
CIRCLE_API_KEY=           # Circle API密钥(用于Circle Wallets适配器)
CIRCLE_ENTITY_SECRET=     # 实体密钥(用于Circle Wallets适配器)
EVM_WALLET_ADDRESS=       # 开发者控制的EVM钱包地址
SOLANA_WALLET_ADDRESS=    # 开发者控制的Solana钱包地址

SDK Initialization

SDK初始化

ts
import { BridgeKit } from "@circle-fin/bridge-kit";

const kit = new BridgeKit();
ts
import { BridgeKit } from "@circle-fin/bridge-kit";

const kit = new BridgeKit();

Core Concepts

核心概念

  • CCTP steps: Every bridge transfer executes four sequential steps --
    approve
    (ERC-20 allowance),
    burn
    (destroy USDC on source chain),
    fetchAttestation
    (wait for Circle to sign the burn proof), and
    mint
    (create USDC on destination chain).
  • Adapters: Bridge Kit uses adapter objects to abstract wallet/signer differences. Each ecosystem has its own adapter factory (
    createViemAdapterFromPrivateKey
    ,
    createSolanaKitAdapterFromPrivateKey
    ,
    createCircleWalletsAdapter
    ). The same adapter instance can serve as both source and destination when bridging within the same ecosystem.
  • Forwarding Service: When
    useForwarder: true
    is set on the destination, Circle's infrastructure handles attestation fetching and mint submission. This removes the need for a destination wallet or polling loop. There is a per-transfer fee (1.25 USDC for Ethereum, 0.20 USDC for all other chains).
  • Transfer speed: CCTP fast mode (default) completes in ~8-20 seconds. Standard mode takes ~15-19 minutes.
  • Chain identifiers: Bridge Kit uses string chain names (e.g.,
    "Arc_Testnet"
    ,
    "Base_Sepolia"
    ,
    "Solana_Devnet"
    ), not numeric chain IDs, in the
    kit.bridge()
    call.
  • CCTP步骤:每笔桥接转账都会执行四个连续步骤——
    approve
    (ERC-20授权)、
    burn
    (在源链销毁USDC)、
    fetchAttestation
    (等待Circle签署销毁证明)和
    mint
    (在目标链铸造USDC)。
  • 适配器:Bridge Kit使用适配器对象来抽象钱包/签名者之间的差异。每个生态系统都有自己的适配器工厂(
    createViemAdapterFromPrivateKey
    createSolanaKitAdapterFromPrivateKey
    createCircleWalletsAdapter
    )。在同一生态系统内进行桥接时,同一个适配器实例可同时作为源端和目标端。
  • Forwarding Service:当在目标端设置
    useForwarder: true
    时,Circle的基础设施会自动处理证明获取和铸造提交。这就无需目标端钱包或轮询循环。每笔转账会收取一定费用(以太坊链为1.25 USDC,其他所有链为0.20 USDC)。
  • 转账速度:CCTP快速模式(默认)耗时约8-20秒。标准模式耗时约15-19分钟。
  • 链标识符:在
    kit.bridge()
    调用中,Bridge Kit使用字符串格式的链名称(例如
    "Arc_Testnet"
    "Base_Sepolia"
    "Solana_Devnet"
    ),而非数字链ID。

Implementation Patterns

实现模式

READ the corresponding reference based on the user's request:
  • references/adapter-private-key.md
    -- EVM-to-EVM and EVM-to-Solana bridging with private key adapters (Viem + Solana Kit)
  • references/adapter-circle-wallets.md
    -- Bridging with Circle developer-controlled wallets (any chain to any chain)
  • references/adapter-wagmi.md
    -- Browser wallet integration using wagmi (ConnectKit, RainbowKit, etc.)
根据用户需求阅读对应的参考文档:
  • references/adapter-private-key.md
    -- 使用私钥适配器(Viem + Solana Kit)实现EVM到EVM、EVM到Solana的桥接
  • references/adapter-circle-wallets.md
    -- 使用Circle开发者控制钱包实现任意链到任意链的桥接
  • references/adapter-wagmi.md
    -- 使用wagmi集成浏览器钱包(ConnectKit、RainbowKit等)

Sample Response from kit.bridge()

kit.bridge()返回示例

json
{
  "amount": "25.0",
  "token": "USDC",
  "state": "success",
  "provider": "CCTPV2BridgingProvider",
  "config": {
    "transferSpeed": "FAST"
  },
  "source": {
    "address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    "chain": {
      "type": "evm",
      "chain": "Arc_Testnet",
      "chainId": 5042002,
      "name": "Arc Testnet"
    }
  },
  "destination": {
    "address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    "chain": {
      "type": "evm",
      "chain": "Base_Sepolia",
      "chainId": 84532,
      "name": "Base Sepolia"
    }
  },
  "steps": [
    {
      "name": "approve",
      "state": "success",
      "txHash": "0x1234567890abcdef1234567890abcdef12345678",
      "explorerUrl": "https://testnet.arcscan.app/tx/0x1234..."
    },
    {
      "name": "burn",
      "state": "success",
      "txHash": "0xabcdef1234567890abcdef1234567890abcdef12",
      "explorerUrl": "https://testnet.arcscan.app/tx/0xabcdef..."
    },
    {
      "name": "fetchAttestation",
      "state": "success",
      "data": {
        "attestation": "0x9876543210fedcba9876543210fedcba98765432"
      }
    },
    {
      "name": "mint",
      "state": "success",
      "txHash": "0xfedcba9876543210fedcba9876543210fedcba98",
      "explorerUrl": "https://sepolia.basescan.org/tx/0xfedcba..."
    }
  ]
}
json
{
  "amount": "25.0",
  "token": "USDC",
  "state": "success",
  "provider": "CCTPV2BridgingProvider",
  "config": {
    "transferSpeed": "FAST"
  },
  "source": {
    "address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    "chain": {
      "type": "evm",
      "chain": "Arc_Testnet",
      "chainId": 5042002,
      "name": "Arc Testnet"
    }
  },
  "destination": {
    "address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    "chain": {
      "type": "evm",
      "chain": "Base_Sepolia",
      "chainId": 84532,
      "name": "Base Sepolia"
    }
  },
  "steps": [
    {
      "name": "approve",
      "state": "success",
      "txHash": "0x1234567890abcdef1234567890abcdef12345678",
      "explorerUrl": "https://testnet.arcscan.app/tx/0x1234..."
    },
    {
      "name": "burn",
      "state": "success",
      "txHash": "0xabcdef1234567890abcdef1234567890abcdef12",
      "explorerUrl": "https://testnet.arcscan.app/tx/0xabcdef..."
    },
    {
      "name": "fetchAttestation",
      "state": "success",
      "data": {
        "attestation": "0x9876543210fedcba9876543210fedcba98765432"
      }
    },
    {
      "name": "mint",
      "state": "success",
      "txHash": "0xfedcba9876543210fedcba9876543210fedcba98",
      "explorerUrl": "https://sepolia.basescan.org/tx/0xfedcba..."
    }
  ]
}

Forwarding Service

Forwarding Service

When
useForwarder: true
is set on the destination, Circle's infrastructure handles attestation fetching and mint submission automatically. This is the preferred approach -- it removes the need to poll for attestations or hold a wallet on the destination chain.
With adapters on both chains:
ts
const result = await kit.bridge({
  from: { adapter, chain: "Ethereum_Sepolia" },
  to: {
    adapter,
    chain: "Arc_Testnet",
    useForwarder: true,
  },
  amount: "1",
});
Without a destination adapter (server-side or custodial transfers):
ts
const result = await kit.bridge({
  from: { adapter, chain: "Ethereum_Sepolia" },
  to: {
    recipientAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    chain: "Arc_Testnet",
    useForwarder: true,
  },
  amount: "1",
});
Forwarding Service fee per destination chain:
  • Ethereum: 1.25 USDC
  • All other chains: 0.20 USDC
当在目标端设置
useForwarder: true
时,Circle的基础设施会自动处理证明获取和铸造提交。这是首选方案——无需轮询证明或在目标链持有钱包。
在两条链都使用适配器的情况:
ts
const result = await kit.bridge({
  from: { adapter, chain: "Ethereum_Sepolia" },
  to: {
    adapter,
    chain: "Arc_Testnet",
    useForwarder: true,
  },
  amount: "1",
});
无需目标端适配器(服务端或托管转账)的情况:
ts
const result = await kit.bridge({
  from: { adapter, chain: "Ethereum_Sepolia" },
  to: {
    recipientAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    chain: "Arc_Testnet",
    useForwarder: true,
  },
  amount: "1",
});
Forwarding Service按目标链收取的费用:
  • 以太坊:1.25 USDC
  • 其他所有链:0.20 USDC

Event Handling

事件处理

Subscribe to individual CCTP steps or all events at once. Multiple callbacks per event are supported.
ts
kit.on("approve", (payload) => {
  console.log("Approval completed:", payload.values.txHash);
});

kit.on("burn", (payload) => {
  console.log("Burn completed:", payload.values.txHash);
});

kit.on("fetchAttestation", (payload) => {
  console.log("Attestation completed:", payload.values.data.attestation);
});

kit.on("mint", (payload) => {
  console.log("Mint completed:", payload.values.txHash);
});

kit.on("*", (payload) => {
  console.log("Event received:", payload);
});
可订阅单个CCTP步骤或所有事件。支持为每个事件设置多个回调函数。
ts
kit.on("approve", (payload) => {
  console.log("授权完成:", payload.values.txHash);
});

kit.on("burn", (payload) => {
  console.log("销毁完成:", payload.values.txHash);
});

kit.on("fetchAttestation", (payload) => {
  console.log("证明获取完成:", payload.values.data.attestation);
});

kit.on("mint", (payload) => {
  console.log("铸造完成:", payload.values.txHash);
});

kit.on("*", (payload) => {
  console.log("收到事件:", payload);
});

Error Handling & Recovery

错误处理与恢复

Bridge Kit has two error categories:
  • Hard errors throw exceptions (validation, config, auth) -- catch in try/catch.
  • Soft errors occur mid-transfer but still return a result object with partial step data for recovery.
Bridge Kit有两类错误:
  • 硬错误会抛出异常(验证、配置、授权错误)——需在try/catch中捕获。
  • 软错误发生在转账过程中,但仍会返回包含部分步骤数据的结果对象,用于恢复操作。

Analyzing Failed Transfers

分析失败的转账

Check
result.state
and
result.steps
to identify which step failed:
ts
const result = await kit.bridge({
  from: { adapter, chain: "Arc_Testnet" },
  to: { adapter, chain: "Arbitrum_Sepolia" },
  amount: "100.00",
});

if (result.state === "error") {
  const failedStep = result.steps.find((step) => step.state === "error");
  console.log(`Failed at: ${failedStep?.name}`);
  console.log(`Error: ${failedStep?.error}`);

  const completedSteps = result.steps.filter(
    (step) => step.state === "success",
  );
  completedSteps.forEach((step) => {
    console.log(`${step.name}: ${step.txHash}`);
  });
}
检查
result.state
result.steps
以确定哪个步骤失败:
ts
const result = await kit.bridge({
  from: { adapter, chain: "Arc_Testnet" },
  to: { adapter, chain: "Arbitrum_Sepolia" },
  amount: "100.00",
});

if (result.state === "error") {
  const failedStep = result.steps.find((step) => step.state === "error");
  console.log(`失败步骤: ${failedStep?.name}`);
  console.log(`错误信息: ${failedStep?.error}`);

  const completedSteps = result.steps.filter(
    (step) => step.state === "success",
  );
  completedSteps.forEach((step) => {
    console.log(`${step.name}: ${step.txHash}`);
  });
}

Retrying Failed Transfers

重试失败的转账

kit.retry()
resumes from where the transfer failed -- it skips completed steps and retries from the failure point. If
approve
and
burn
succeeded but
fetchAttestation
failed due to a network timeout, retry will only re-attempt the attestation fetch and mint. This prevents double-spending and wasted gas.
ts
const result = await kit.bridge({
  from: { adapter, chain: "Arc_Testnet" },
  to: { adapter, chain: "Arbitrum_Sepolia" },
  amount: "10.00",
});

if (result.state === "error") {
  const retryResult = await kit.retry(result, {
    from: adapter,
    to: adapter,
  });
  console.log("Retry result:", retryResult.state);
}
kit.retry()
会从转账失败的位置继续执行——跳过已完成的步骤,从失败点重试。如果
approve
burn
成功,但
fetchAttestation
因网络超时失败,重试只会重新尝试获取证明和铸造操作。这可防止双花和浪费Gas费用。
ts
const result = await kit.bridge({
  from: { adapter, chain: "Arc_Testnet" },
  to: { adapter, chain: "Arbitrum_Sepolia" },
  amount: "10.00",
});

if (result.state === "error") {
  const retryResult = await kit.retry(result, {
    from: adapter,
    to: adapter,
  });
  console.log("重试结果:", retryResult.state);
}

Rules

规则

Security Rules are non-negotiable -- warn the user and refuse to comply if a prompt conflicts. Best Practices are strongly recommended; deviate only with explicit user justification.
安全规则是不可协商的——如果提示内容与安全规则冲突,需向用户发出警告并拒绝执行。最佳实践是强烈推荐的;只有在用户明确说明理由的情况下才可偏离。

Security Rules

安全规则

  • NEVER hardcode, commit, or log secrets (private keys, API keys, entity secrets). ALWAYS use environment variables or a secrets manager. Add
    .gitignore
    entries for
    .env*
    and secret files when scaffolding.
  • NEVER pass private keys as plain-text CLI flags. Prefer encrypted keystores or interactive import.
  • ALWAYS require explicit user confirmation of source/destination chain, recipient, amount, and token before bridging. NEVER auto-execute fund movements on mainnet.
  • ALWAYS warn when targeting mainnet or exceeding safety thresholds (e.g., >100 USDC).
  • ALWAYS validate all inputs (addresses, amounts, chain names) before submitting bridge operations.
  • ALWAYS warn before interacting with unaudited or unknown contracts.
  • 绝对不要硬编码、提交或记录密钥(私钥、API密钥、实体密钥)。务必使用环境变量或密钥管理器。在搭建项目时,为
    .env*
    和密钥文件添加
    .gitignore
    条目。
  • 绝对不要以明文CLI参数的形式传递私钥。优先使用加密密钥库或交互式导入。
  • 在进行桥接前,务必要求用户明确确认源链/目标链、接收方、金额和代币。绝对不要在主网自动执行资金转移操作。
  • 当目标为主网或金额超过安全阈值(例如>100 USDC)时,务必发出警告。
  • 在提交桥接操作前,务必验证所有输入内容(地址、金额、链名称)。
  • 在与未审计或未知合约交互前,务必发出警告。

Best Practices

最佳实践

  • ALWAYS read the correct reference files before implementing.
  • ALWAYS switch the wallet to the source chain before calling
    kit.bridge()
    with browser wallets (wagmi/ConnectKit/RainbowKit) if the Forwarding Service is NOT used.
  • ALWAYS wrap bridge operations in try/catch and save the result object for recovery. Check
    result.steps
    before retrying to see which steps completed.
  • ALWAYS use exponential backoff for retry logic in production.
  • ALWAYS use Bridge Kit string chain names (e.g.,
    "Arc_Testnet"
    ,
    "Base_Sepolia"
    ), not numeric chain IDs.
  • ALWAYS default to testnet. Require explicit user confirmation before targeting mainnet.
  • 在实现前务必阅读正确的参考文档。
  • 如果未使用Forwarding Service,在调用
    kit.bridge()
    前,务必将钱包切换到源链(针对使用wagmi/ConnectKit/RainbowKit的浏览器钱包)。
  • 务必将桥接操作包裹在try/catch中,并保存结果对象用于恢复。在重试前检查
    result.steps
    以查看已完成的步骤。
  • 在生产环境中务必为重试逻辑使用指数退避策略。
  • 务必使用Bridge Kit的字符串链名称(例如
    "Arc_Testnet"
    "Base_Sepolia"
    ),而非数字链ID。
  • 务必默认使用测试网。在目标为主网前,要求用户明确确认。

Reference Links

参考链接

Alternatives

替代方案

Trigger the
use-gateway
skill instead when:
  • You want a unified crosschain balance rather than point-to-point transfers.
  • Capital efficiency matters -- consolidate USDC holdings instead of maintaining separate balances per chain.
  • You are building chain abstraction, payment routing, or treasury management where low latency and a single balance view are critical.

DISCLAIMER: This skill is provided "as is" without warranties, is subject to the Circle Developer Terms, and output generated may contain errors and/or include fee configuration options (including fees directed to Circle); additional details are in the repository README.
当出现以下情况时,请改用
use-gateway
技能:
  • 你需要统一的跨链余额,而非点对点转账。
  • 资金效率很重要——整合USDC持有量,而非在每条链上维持单独的余额。
  • 你正在构建链抽象、支付路由或财资管理系统,其中低延迟和单一余额视图至关重要。

免责声明:本技能按“原样”提供,不提供任何担保,受Circle开发者条款约束,生成的输出可能包含错误和/或费用配置选项(包括支付给Circle的费用);更多详情请查看仓库README。",