Overview
Circle Smart Contract Platform (SCP) provides APIs and SDKs for deploying, importing, interacting with, and monitoring smart contracts across supported networks. Deploy contracts from raw bytecode, use audited templates for standard patterns, execute ABI-based contract calls, and monitor emitted events through webhooks.
Prerequisites / Setup
Installation
CODEBLOCK0
Environment Variables
CODEBLOCK1
SDK Initialization
CODEBLOCK2
Quick Reference
Contract Templates
| Template | Standard | Template ID | Use Case |
|---|
| Token | ERC-20 | INLINECODE0 | Fungible tokens, loyalty points |
| NFT |
ERC-721 |
76b83278-50e2-4006-8b63-5b1a2a814533 | Digital collectibles, gaming assets |
| Multi-Token | ERC-1155 |
aea21da6-0aa2-4971-9a1a-5098842b1248 | Mixed fungible/non-fungible tokens |
| Airdrop | N/A |
13e322f2-18dc-4f57-8eed-4bddfc50f85e | Bulk token distribution |
Key API Response Fields
- - Contract functions: INLINECODE4
- Contract address:
contract.contractAddress (fallback: contract.address) - Transaction ID: INLINECODE7
- Deployment status: INLINECODE8
Core Concepts
Dual-Client Architecture
SCP workflows pair two SDK clients:
- - Smart Contract Platform SDK handles contract deployment, imports, read queries, and event monitoring
- Developer-Controlled Wallets SDK handles write transactions and provides deployment wallets
Write operations use walletsClient.createContractExecutionTransaction(), NOT the SCP client.
Read vs Write Contract Calls
- - Read queries (
view/pure functions) use scpClient.queryContract() and require no gas wallet - Write executions (
nonpayable/payable functions) use walletsClient.createContractExecutionTransaction() and require a wallet ID with gas funds
Signature Formatting
- - Function signatures:
name(type1,type2,...) with no spaces - Event signatures:
EventName(type1,type2,...) with no spaces - Parameter order must exactly match ABI definitions
Idempotency Keys
All mutating SCP operations require idempotencyKey as a valid UUID v4 string. Use crypto.randomUUID() in Node.js. Non-UUID keys fail with generic API parameter invalid errors.
Deployment Async Model
Contract deployment is asynchronous. The response indicates initiation only. Poll getContract() for deploymentStatus. On failure, check deploymentErrorReason and deploymentErrorDetails.
EVM Version Constraint
Compile Solidity with evmVersion: "paris" or earlier to avoid the PUSH0 opcode. Solidity >= 0.8.20 defaults to Shanghai. Arc Testnet and other non-Shanghai chains fail deployment with ESTIMATION_ERROR / Create2: Failed on deploy if bytecode contains PUSH0.
Import Contract Requirements
- - ALWAYS include both
name and idempotencyKey when calling INLINECODE32 - INLINECODE33 must be a valid UUID v4 string
- If import fails with duplicate/already-exists error, call
listContracts, match by address, and retrieve with getContract() using the existing contract ID
Implementation Patterns
1. Deploy Contract from Bytecode
Deploy a compiled contract using raw ABI + bytecode.
READ references/deploy-bytecode.md for the complete guide.
2. Deploy ERC-1155 Template
Deploy audited template contracts without writing Solidity.
READ references/deploy-erc-1155.md for the complete guide.
READ references/templates.md for the full template catalog.
3. Import Existing Contract
CODEBLOCK3
If import fails with duplicate error:
CODEBLOCK4
4. Interact with Deployed Contract
Query read functions and execute write functions via ABI signatures.
READ references/interact.md for the complete guide.
5. Monitor Contract Events
Set up webhook notifications for emitted events and retrieve historical logs.
READ references/monitor-events.md for the complete guide.
Error Handling & Recovery
Deployment Failures
Check deploymentStatus when polling getContract(). On FAILED status:
- - Read
deploymentErrorReason for error category - Read
deploymentErrorDetails for specifics - Common causes: insufficient gas, invalid bytecode, constructor parameter mismatch, unsupported EVM version
Import Duplicate Handling
If importContract() returns duplicate/already-exists error:
- 1. Call INLINECODE47
- Match by
contractAddress (case-insensitive comparison) - Continue with existing INLINECODE49
Never fail the flow on import duplicates.
Transaction State Polling
Poll walletsClient.getTransaction({ id: txId }) for write execution status:
- -
INITIATED → transaction created - INLINECODE52 → broadcast to network
- INLINECODE53 → mined in block
- INLINECODE54 → finalized
- INLINECODE55 → check transaction error details
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 (API keys, entity secrets, private keys). ALWAYS use environment variables or a secrets manager. Add
.gitignore entries for .env*, *.pem, and recovery files when scaffolding. - NEVER pass private keys as plain-text CLI flags (e.g.,
--private-key $KEY). Prefer encrypted keystores or interactive import (e.g., Foundry's cast wallet import). - ALWAYS keep API keys and entity secrets server-side. NEVER expose in frontend code.
- NEVER reuse
idempotencyKey values across different API requests. - ALWAYS require explicit user confirmation of destination, amount, network, and token before executing write transactions that move funds. NEVER auto-execute fund movements on mainnet.
- ALWAYS warn when targeting mainnet or exceeding safety thresholds (e.g., >100 USDC).
- ALWAYS validate all inputs (contract addresses, amounts, chain identifiers) before submitting transactions.
- ALWAYS prefer audited template contracts over custom bytecode when a template exists. Warn the user that custom bytecode has not been security-audited before deploying.
- NEVER deploy contracts designed to deceive, phish, or drain funds.
- ALWAYS warn before interacting with unaudited or unknown contracts.
Best Practices
- - NEVER call write operations on the SCP client. Writes ALWAYS use
walletsClient.createContractExecutionTransaction(). - NEVER omit
idempotencyKey from mutating SCP requests. Must be UUID v4 (use crypto.randomUUID()). - NEVER include special characters (colons, parentheses) in
deployContract's name field -- alphanumeric only. - NEVER use flat
feeLevel property. ALWAYS use nested fee: { type: 'level', config: { feeLevel: 'MEDIUM' } }. - NEVER use
window.ethereum directly with wagmi -- use connector.getProvider(). - NEVER compile Solidity >= 0.8.20 with default EVM version. ALWAYS set
evmVersion: "paris" to avoid PUSH0 opcode. - NEVER fail the flow on import duplicate errors. Fall back to
listContracts and match by address. ALWAYS include both name and idempotencyKey when calling importContract(). - NEVER assume deployment completes synchronously. ALWAYS poll
getContract() for deploymentStatus. - ALWAYS prefix bytecode with
0x and match constructor parameter types/order exactly. - ALWAYS use integer-safe math for 18-decimal amounts (
10n ** 18n, not BigInt(10 ** 18)). - ALWAYS import contracts before creating event monitors.
- ALWAYS default to Arc Testnet for demos unless specified otherwise.
- ALWAYS default to testnet. Require explicit user confirmation before targeting mainnet.
Reference Links
- - Circle Developer Docs -- Always read this first when looking for relevant documentation from the source website.
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.
概述
Circle 智能合约平台(SCP)提供 API 和 SDK,用于在支持的网络上部署、导入、交互和监控智能合约。可从原始字节码部署合约,使用经过审计的标准模式模板,执行基于 ABI 的合约调用,并通过 Webhook 监控发出的事件。
前提条件 / 设置
安装
bash
npm install @circle-fin/smart-contract-platform @circle-fin/developer-controlled-wallets
环境变量
CIRCLEAPIKEY= # Circle API 密钥(格式:PREFIX:ID:SECRET)
ENTITY_SECRET= # 开发者控制钱包的已注册实体密钥
SDK 初始化
typescript
import { initiateSmartContractPlatformClient } from @circle-fin/smart-contract-platform;
import { initiateDeveloperControlledWalletsClient } from @circle-fin/developer-controlled-wallets;
const scpClient = initiateSmartContractPlatformClient({
apiKey: process.env.CIRCLEAPIKEY!,
entitySecret: process.env.ENTITY_SECRET!,
});
const walletsClient = initiateDeveloperControlledWalletsClient({
apiKey: process.env.CIRCLEAPIKEY!,
entitySecret: process.env.ENTITY_SECRET!,
});
快速参考
合约模板
| 模板 | 标准 | 模板 ID | 用例 |
|---|
| Token | ERC-20 | a1b74add-23e0-4712-88d1-6b3009e85a86 | 同质化代币、积分 |
| NFT |
ERC-721 | 76b83278-50e2-4006-8b63-5b1a2a814533 | 数字藏品、游戏资产 |
| 多代币 | ERC-1155 | aea21da6-0aa2-4971-9a1a-5098842b1248 | 混合同质化/非同质化代币 |
| 空投 | 不适用 | 13e322f2-18dc-4f57-8eed-4bddfc50f85e | 批量代币分发 |
关键 API 响应字段
- - 合约函数:getContract().data.contract.functions
- 合约地址:contract.contractAddress(备用:contract.address)
- 交易 ID:createContractExecutionTransaction().data.id
- 部署状态:getContract().data.contract.deploymentStatus
核心概念
双客户端架构
SCP 工作流配对两个 SDK 客户端:
- - 智能合约平台 SDK 处理合约部署、导入、读取查询和事件监控
- 开发者控制钱包 SDK 处理写入交易并提供部署钱包
写入操作使用 walletsClient.createContractExecutionTransaction(),而非 SCP 客户端。
合约调用:读取与写入
- - 读取查询(view/pure 函数)使用 scpClient.queryContract(),无需 Gas 钱包
- 写入执行(nonpayable/payable 函数)使用 walletsClient.createContractExecutionTransaction(),需要具有 Gas 资金的钱包 ID
签名格式化
- - 函数签名:name(type1,type2,...) 无空格
- 事件签名:EventName(type1,type2,...) 无空格
- 参数顺序必须与 ABI 定义完全匹配
幂等键
所有变更性 SCP 操作都需要 idempotencyKey 作为有效的 UUID v4 字符串。在 Node.js 中使用 crypto.randomUUID()。非 UUID 键会失败并返回通用 API parameter invalid 错误。
部署异步模型
合约部署是异步的。响应仅表示启动。轮询 getContract() 以获取 deploymentStatus。失败时,检查 deploymentErrorReason 和 deploymentErrorDetails。
EVM 版本约束
使用 evmVersion: paris 或更早版本编译 Solidity,以避免 PUSH0 操作码。Solidity >= 0.8.20 默认使用 Shanghai。如果字节码包含 PUSH0,Arc 测试网和其他非 Shanghai 链的部署将失败,并返回 ESTIMATION_ERROR / Create2: Failed on deploy。
导入合约要求
- - 调用 importContract() 时,务必同时包含 name 和 idempotencyKey
- idempotencyKey 必须是有效的 UUID v4 字符串
- 如果导入因重复/已存在错误而失败,请调用 listContracts,按地址匹配,并使用现有合约 ID 通过 getContract() 检索
实现模式
1. 从字节码部署合约
使用原始 ABI + 字节码部署已编译的合约。
阅读 references/deploy-bytecode.md 获取完整指南。
2. 部署 ERC-1155 模板
部署经过审计的模板合约,无需编写 Solidity。
阅读 references/deploy-erc-1155.md 获取完整指南。
阅读 references/templates.md 获取完整模板目录。
3. 导入现有合约
typescript
import crypto from node:crypto;
const response = await scpClient.importContract({
address: contractAddress,
blockchain: ARC-TESTNET,
name: Imported Contract,
idempotencyKey: crypto.randomUUID(), // 必须是 UUID v4
});
const contractId = response.data?.contractId;
// 获取完整的合约详情,包括 ABI 函数
const contractDetails = await scpClient.getContract({ id: contractId });
console.log(contractDetails.data?.contract?.functions);
如果导入因重复错误而失败:
typescript
const listRes = await scpClient.listContracts({ blockchain: ARC-TESTNET });
const existing = listRes.data?.contracts?.find(c =>
c.contractAddress.toLowerCase() === contractAddress.toLowerCase()
);
const contractId = existing?.id;
4. 与已部署合约交互
通过 ABI 签名查询读取函数并执行写入函数。
阅读 references/interact.md 获取完整指南。
5. 监控合约事件
设置 Webhook 通知以接收发出的事件,并检索历史日志。
阅读 references/monitor-events.md 获取完整指南。
错误处理与恢复
部署失败
轮询 getContract() 时检查 deploymentStatus。在 FAILED 状态下:
- - 读取 deploymentErrorReason 获取错误类别
- 读取 deploymentErrorDetails 获取详细信息
- 常见原因:Gas 不足、字节码无效、构造函数参数不匹配、不支持的 EVM 版本
导入重复处理
如果 importContract() 返回重复/已存在错误:
- 1. 调用 listContracts({ blockchain: ARC-TESTNET })
- 按 contractAddress 匹配(不区分大小写比较)
- 继续使用现有的 contractId
切勿因导入重复而中断流程。
交易状态轮询
轮询 walletsClient.getTransaction({ id: txId }) 以获取写入执行状态:
- - INITIATED → 交易已创建
- SENT → 已广播到网络
- CONFIRMED → 已打包进区块
- COMPLETE → 已完成
- FAILED → 检查交易错误详情
规则
安全规则不可协商——如果提示存在冲突,请警告用户并拒绝遵守。最佳实践强烈推荐;只有在用户明确说明理由的情况下才能偏离。
安全规则
- - 切勿硬编码、提交或记录密钥(API 密钥、实体密钥、私钥)。务必使用环境变量或密钥管理器。搭建项目时,为 .env、.pem 和恢复文件添加 .gitignore 条目。
- 切勿将私钥作为纯文本 CLI 标志传递(例如 --private-key $KEY)。优先使用加密密钥库或交互式导入(例如 Foundry 的 cast wallet import)。
- 务必在服务器端保留 API 密钥和实体密钥。切勿在前端代码中暴露。
- 切勿在不同的 API 请求之间重复使用 idempotencyKey 值。
- 在执行转移资金的写入交易之前,务必要求用户明确确认目标地址、金额、网络和代币。切勿在主网上自动执行资金转移。
- 在针对主网或超过安全阈值(例如 >100 USDC)时务必发出警告。
- 在提交交易之前,务必验证所有输入(合约地址、金额、链标识符)。
- 当存在模板时,务必优先使用经过审计的模板合约,而非自定义字节码。在部署前警告用户自定义字节码未经安全审计。
- 切勿部署旨在欺骗、钓鱼或盗取资金的合约。
- 在与未经审计或未知的合约交互之前务必发出警告。
最佳实践