统一余额套件
目录
概览
Stablecoin Kit生态系统是Circle的开源努力,用SDK来简化稳定coin的开发,这些SDK易于正确使用并难以被滥用. Kit是跨框架的 (viem, ethers, @solana/web3) , 并且干净地融入到任何堆栈中 。 他们有明智的默认, 但提供逃生舱门 完全控制。 一个可插接的架构使执行具有灵活性,所有工具包都具有互通性,因此可以编组,以适应广泛的使用案例.
统一平衡工具包为通过Circle's Gateway协议的跨链USDC操作提供了高层次抽象. 存款、支出(薄荷)和查询平衡跨越多个链条,使用简单的方法调用——没有人工连接步骤,没有流动资金预先到位,没有正常支出流动的链上延误.
使用 spend 用于正常脱离统一平衡. removeFund 在无法正常支出流动的情况下,它是一种无信任的回收途径,需要7天的提款后才能取出资金.
为什么是统一平衡套?
- 统一平衡模式: 单一抽象的存款、支出和跨链的平衡查询
- * 即时跨链移动: 在一个流中从多个源链和目的地取出薄荷
- 带回自己的适配器: 使用viem,醚或@solana/web3.js适配器
- 生产准备: 有证明和确定性流动的Leverages Circle's Gateway v1
- QQ 开发者经验: 完整类型脚本支持,全面验证,以及结构错误
- 多来源支出: 在一个单一支出操作中从多个链中分配金额
- 强力错误处理: 有可回收性和再试支持的结构化 KitError
- 事件监测:跟踪存款、支出和结余业务的生命周期活动
建筑流程
统一平衡套件采用为灵活性和类型安全设计的三层结构:
┌─────────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Unified Balance │────│ Provider │────│ Adapter │
│ Kit (Orchestrator) │ │ (Gateway v1) │ │ (Blockchain) │
└─────────────────────┘ └──────────────────┘ └─────────────────┘
- 适配器: 处理特定区块链操作(钱包、交易、气体),并允许您使用任何您自在的框架(viem、ethes、@solana/web3.js)
- 提供者: 执行网关协议(目前为网关 v1)
- 统一余额套件: 具有验证和路由的管弦乐器和提供商
这种分离确保每个组成部分都承担单一的责任,同时在整个跨链生命周期中保持无缝的一体化.
安装
npm install @circle-fin/unified-balance-kit
# or
yarn add @circle-fin/unified-balance-kit
适配器
选择目标链的适当适配器 :
# For EVM chains (Ethereum, Base, Arbitrum, etc.)
npm install @circle-fin/adapter-viem-v2 viem
# or
yarn add @circle-fin/adapter-viem-v2 viem
# For EVM chains using Ethers.js
npm install @circle-fin/adapter-ethers-v6
# or
yarn add @circle-fin/adapter-ethers-v6
# For Solana
npm install @circle-fin/adapter-solana @solana/web3.js
# or
yarn add @circle-fin/adapter-solana @solana/web3.js
快速启动
最轻松的设置:存款和开支
最好还是:快速启动,简单的存款和跨链支出
import {
createUnifiedBalanceKitContext,
deposit,
spend,
} from '@circle-fin/unified-balance-kit'
import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
// Create context with default Gateway v1 provider
const context = createUnifiedBalanceKitContext()
// Create adapter that works across chains
const adapter = createViemAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
})
// Deposit USDC on Ethereum
await deposit(context, {
from: { adapter, chain: 'Ethereum' },
amount: '100',
})
// Spend (mint) USDC on Base by pulling from Ethereum
const result = await spend(context, {
amount: '50',
from: {
adapter,
allocations: { amount: '50', chain: 'Ethereum' },
},
to: { adapter, chain: 'Base' },
})
console.log('Spend tx:', result.txHash, result.explorerUrl)
QQ 发送到不同的地址
最好还是:向他人钱包,保管服务送出资金
使用 recipientAddress 当收件人与适配器的地址不同时:
const result = await spend(context, {
amount: '50',
from: {
adapter,
allocations: { amount: '50', chain: 'Ethereum' },
},
to: {
adapter,
chain: 'Base',
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
},
})
QQ 查询余额
最好还是: 显示合计或每链USDC余额
import {
createUnifiedBalanceKitContext,
getBalances,
} from '@circle-fin/unified-balance-kit'
const context = createUnifiedBalanceKitContext()
const adapter = createViemAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
})
// Get confirmed balances across all supported chains
const balances = await getBalances(context, {
sources: { adapter },
})
console.log('Confirmed:', balances.totalConfirmedBalance)
// Include pending deposits in the result
const withPending = await getBalances(context, {
sources: { adapter },
includePending: true,
})
console.log('Confirmed:', withPending.totalConfirmedBalance)
console.log('Pending:', withPending.totalPendingBalance)
成本估算
最好还是: 支出前显示用户费用
import {
createUnifiedBalanceKitContext,
estimateSpend,
} from '@circle-fin/unified-balance-kit'
const context = createUnifiedBalanceKitContext()
const estimate = await estimateSpend(context, {
amount: '100',
from: {
adapter,
allocations: { amount: '100', chain: 'Ethereum' },
},
to: { adapter, chain: 'Base' },
})
console.log('Estimated fees:', estimate.fees)
配置
Kit 语境
套件使用一个持有提供者的上下文对象. 创建它与 createUnifiedBalanceKitContext数字 :
// Default: Gateway v1 provider
const context = createUnifiedBalanceKitContext()
// Or with additional providers
const customContext = createUnifiedBalanceKitContext({
providers: [myCustomProvider],
})
支出参数
// Single source allocation
const spendParams = {
amount: '100',
from: {
adapter,
allocations: { amount: '100', chain: 'Ethereum' },
},
to: { adapter, chain: 'Base' },
}
// Multi-source allocation (pull from multiple chains)
const multiSourceSpend = {
amount: '100',
from: {
adapter,
allocations: [
{ amount: '50', chain: 'Ethereum' },
{ amount: '50', chain: 'Base' },
],
},
to: { adapter, chain: 'Avalanche' },
}
平衡参数
// By adapter (wallet-controlled)
const balances = await getBalances(context, {
sources: { adapter },
})
// By address (read-only, no adapter needed)
const balancesByAddress = await getBalances(context, {
sources: { address: '0x...', chains: ['Ethereum', 'Base'] },
})
自定义收费
该工具包为支出业务提供定制费。 收费附加在转账金额外. 使用类 API 与 setCustomFeePolicy 或通过 config.customFee 每笔开支:
import { UnifiedBalanceKit } from '@circle-fin/unified-balance-kit'
const kit = new UnifiedBalanceKit()
// Kit-level policy (class API)
kit.setCustomFeePolicy({
computeFee: (params) => {
const total = parseFloat(params.amount)
return (total * 0.01).toFixed(6) // 1%
},
resolveFeeRecipientAddress: (destinationChain) => {
return destinationChain.type === 'solana'
? 'SolanaAddressBase58...'
: '0xEvmAddress...'
},
})
// Or per-spend override (works with both APIs)
await spend(context, {
amount: '100',
from: { adapter, allocations: { amount: '100', chain: 'Ethereum' } },
to: { adapter, chain: 'Base' },
config: {
customFee: {
value: '1.0',
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
},
},
})
跨链式收费人
spend() 能够从多个源链中提取资金(例如结合一个EVM)
和索拉纳的来源,但每个费用支付 在花薄荷薄荷 不变
单一目的地链 -你通过的那个 to。 。 destinationChain
上面永远是支出的目的地 从来不是源链 准确的说
每个支出都解决一个收款地址(在该目的地有效).
如果你花在不同的目的地链类型 跨呼叫(一些花费)
到 EVM 链, 其它到索拉纳), 配置 setFeeRecipients 一次与一个
用于每个链条类型的地址, 而不是写入链- 分支逻辑
你自己来. setFeeRecipients 只影响使用哪个收件人地址
-你还需要 setCustomFeePolicy是因为 computeFee 确定收费
金额. 通话 setFeeRecipients 永远不要打电话
setCustomFeePolicy 浪费时间抛出( 没有) computeFee 改为
确定一个数量:
kit.setCustomFeePolicy({
computeFee: (params) => (parseFloat(params.amount) * 0.01).toFixed(6), // 1%
})
kit.setFeeRecipients({
evm: '0xEvmAddress...',
solana: 'SolanaAddressBase58...',
})
工具箱花时间将已解决的目的地链绘制到其链式
(单位:千美元)'evm' 或者说 'solana' 今天),并查看了匹配的条目.
setFeeRecipients 拥有优先级 resolveFeeRecipientAddress 用于任何
其有条目的链式类型——从未为此引用回调
类型。 如果地图缺少解析目的地链条的条目
类型和 a resolveFeeRecipientAddress 调用已配置, 该
套件返回到缺失类型的回调( 已登录警告)
所以,倒计时不是 一个沉默的惊喜。 花费在任何费用之前
只有在地图或召回无法时才尝试收藏
解析目的地链式类型的地址。 现有一体化
仅使用 resolveFeeRecipientAddress 或单弦 recipientAddress
继续工作不变.
处理错误
该工具包采用结构化 KitError 具有一致属性的实例 :
- 代码: 数字错误代码( 如 1001, 5001)
- 名称:人可读取的ID(例如,
INPUT_VALIDATION_FAILED, (中文(简体) ),ONCHAIN_TRANSACTION_REVERTED(中文(简体) ) - 类型: 错误类别 (E)
INPUT, (中文(简体) ),BALANCE, (中文(简体) ),ONCHAIN, (中文(简体) ),RPC, (中文(简体) ),NETWORK(中文(简体) ) - 可回收性数字 :
FATAL, (中文(简体) ),RETRYABLE,或RESUMABLE - 消息: 方便用户的解释
- 事业。 追踪: 调试的额外上下文
import {
createUnifiedBalanceKitContext,
spend,
KitError,
isKitError,
getErrorCode,
} from '@circle-fin/unified-balance-kit'
const context = createUnifiedBalanceKitContext()
try {
await spend(context, params)
} catch (error) {
if (isKitError(error)) {
console.error(`Error ${error.code}: ${error.name}`, error.message)
if (error.recoverability === 'RESUMABLE' && error.cause?.trace) {
// Handle retry (see Retrying Failed Mints)
}
}
throw error
}
重试失败的薄荷
当交易完成后链上薄荷步骤失败( 资金锁定), 套件会丢入 KitError 与 recoverability: 'RESUMABLE' 财务报告和审定财务报表 attestation编号 :signature 内 cause.trace启用 config.retry 重新尝试.
在索拉纳岛上,薄荷不会创建收款人代币账户. 下面的两个错误都列出缺少的账户 cause.trace.missingTokenAccounts如果缺失的账户属于圆形收费接受者,则联系圆形支持.
- 转移前 (非前导者花费和
estimateSpend:spend在提交任何转帐之前,先检查收款人代号账户。 缺少的账户丢出VALIDATION_FAILEDKitError这是FATAL创建账户,然后调用spend再来一次. - 薄荷时间 (例如关于
config.retry: 缺失的账户丢出VALIDATION_FAILEDKitError这是RESUMABLE重试前创建账户config.retry; 重试先以相同的错误失败 .
try {
const result = await spend(context, params)
console.log('Success:', result.txHash)
} catch (error) {
if (
error instanceof KitError &&
error.recoverability === 'RESUMABLE' &&
error.cause?.trace
) {
const { attestation, signature, missingTokenAccounts } = error.cause
.trace as {
attestation: string
signature: string
missingTokenAccounts?: { tokenAccount: string; mint: string }[]
}
if (missingTokenAccounts?.length) {
// Solana only: create the listed token accounts first, then retry
// with the same attestation. Retrying now fails the same way.
throw error
}
// Retry with the attestation
const result = await spend(context, {
...params,
config: { retry: { attestation, signature } },
})
console.log('Retry success:', result.txHash)
} else {
throw error
}
}
API 参考
核心方法
| 方法 | 说明 |
|---|---|
deposit(context, params) | 将支持的代币存入连锁电话的账户 |
depositFor(context, params) | 将一个支持的令牌存入另一个账户 |
spend(context, params) | 从源头将一个支持的令牌花在目的地链上 |
estimateSpend(context, params) | 在支出前获得费用估计 |
getBalances(context, params) | 查询合计和每链余额 |
getSupportedChains(context, token?, options?) | 获得配置提供者支持的链条 |
addDelegate(context, params) | 为账户增加一个代表 |
removeDelegate(context, params) | 删除代表 |
getDelegateStatus(context, params) | 检查代表状态 : 'none', (中文(简体) ), 'pending',或 'ready' |
initiateRemoveFund(context, params) | 开始只收回资金和推迟7天 |
removeFund(context, params) | 在拖延了7天之后完全清除仅回收的资金 |
使用 spend 用于正常脱离统一平衡。 使用 removeFund
只有在正常支出流量不可用时作为无信任的恢复路径.
网关支持 USDC, cirBTC, 以及 EURC, 每个令牌都有配置
地址 电话 检查 getSupportedChains(context, token) 在选择链条之前.
FAST跨链矿床使用CCTP v2,只接受USDC.
在EVM和索拉纳上,代表权限是每个令牌. 授权的一名代表
(c) 在单独授权使用欧元之前,不得使用欧元.
对于欧元公司向索拉纳支付的费用,收款人和任何定制费收款人必须
已经有一个 EURC 相关符号账户。 SDK 不创建这些
账户。 在开销前创建它们。 如果有一个不见了, spend 之前失败
签名; 创建账户并呼叫 spend 再来一次.
代表地位和最终地位
打电话后 addDelegate,该代表可能无法立即用于 spend 打开
具有缓慢终极性的链条(例如Ethereum, Base, Arbitrum). getDelegateStatus 返回时
反映 Gateway 最终视图的 三态 :
const status = await kit.getDelegateStatus({ from, delegateAddress })
if (status === 'ready') { await kit.spend(...) }
if (status === 'pending') { /* poll until 'ready' */ }
'none'——不是链上代表'pending'——代表设定上线,但"网关"尚未定稿;支出将失败'ready'- 在Gateway完成;支出将取得成功
功能与类 API
函数 API (建议):
import {
createUnifiedBalanceKitContext,
deposit,
spend,
getBalances,
} from '@circle-fin/unified-balance-kit'
const context = createUnifiedBalanceKitContext()
await deposit(context, { from: { adapter, chain: 'Ethereum' }, amount: '100' })
const result = await spend(context, {
amount: '50',
from: { adapter, allocations: { amount: '50', chain: 'Ethereum' } },
to: { adapter, chain: 'Base' },
})
const balances = await getBalances(context, { sources: { adapter } })
类 API数字 :
import { UnifiedBalanceKit } from '@circle-fin/unified-balance-kit'
const kit = new UnifiedBalanceKit()
kit.on('gateway.deposit.succeeded', (payload) => {
console.log('Deposit succeeded:', payload.data)
})
kit.on('gateway.spend.succeeded', (payload) => {
console.log('Spend succeeded:', payload.data.txHash)
})
await kit.deposit({ from: { adapter, chain: 'Ethereum' }, amount: '100' })
const result = await kit.spend({
amount: '50',
from: { adapter, allocations: { amount: '50', chain: 'Ethereum' } },
to: { adapter, chain: 'Base' },
})
发展
大楼
# From the root of the monorepo
nx build @circle-fin/unified-balance-kit
测试
# From the root of the monorepo
nx test @circle-fin/unified-balance-kit
地方发展
# Install dependencies
yarn install
# Build all packages
yarn build
# Build the unified-balance-kit specifically
nx build @circle-fin/unified-balance-kit
# Run tests
nx test @circle-fin/unified-balance-kit
社区与支持
- 调和数字 : 加入我们的社区
许可证
这个项目根据Apache 2.0许可证获得许可. 联系人 支助 详细情况.