use-user-controlled-wallets
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOverview
概述
User-controlled wallets are non-custodial wallets where end users maintain control over their private keys and assets. Users authorize all sensitive operations (transactions, signing, wallet creation) through a challenge-response model that ensures user consent before execution. Multi-chain support includes EVM chains, Solana, and Aptos.
用户控制钱包是一种非托管钱包,最终用户可掌控自己的私钥和资产。所有敏感操作(交易、签名、钱包创建)都通过挑战-响应模型进行授权,确保执行前获得用户同意。多链支持包括EVM链、Solana和Aptos。
Prerequisites / Setup
前提条件/设置
Installation
安装
bash
npm install @circle-fin/user-controlled-wallets@latest @circle-fin/w3s-pw-web-sdk@latest vite-plugin-node-polyfillsbash
npm install @circle-fin/user-controlled-wallets@latest @circle-fin/w3s-pw-web-sdk@latest vite-plugin-node-polyfillsVite Configuration
Vite配置
The SDKs depends on Node.js built-ins (, , etc.) that are not available in the browser. Add to your Vite config:
buffercryptovite-plugin-node-polyfillstypescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [react(), nodePolyfills()],
});SDK依赖Node.js内置模块(、等),这些模块在浏览器中不可用。请在Vite配置中添加:
buffercryptovite-plugin-node-polyfillstypescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [react(), nodePolyfills()],
});Environment Variables
环境变量
bash
undefinedbash
undefinedBackend
后端
CIRCLE_API_KEY= # Circle API key
CIRCLE_API_KEY= # Circle API密钥
Frontend
前端
CIRCLE_APP_ID= # App ID from Wallets > User Controlled > Configurator
undefinedCIRCLE_APP_ID= # 来自钱包>用户控制>配置器的应用ID
undefinedCore Concepts
核心概念
Account Types
账户类型
User-controlled wallets support EOA and SCA account types, chosen at wallet creation.
EOA (Externally Owned Account): No creation fees, higher TPS, broadest chain support (EVM, Solana, Aptos). Requires native tokens for gas on EVM chains. Gas sponsorship only available on Solana via .
feePayerSCA (Smart Contract Account): ERC-4337 account abstraction. Gas sponsorship via Circle Gas Station paymaster, batch operations, flexible key management. EVM-only (no Solana/Aptos). First outbound transaction incurs gas for lazy deployment. Avoid on Ethereum mainnet due to high gas -- use on L2s (Arbitrum, Base, Polygon, Optimism).
For supported blockchains by account type: https://developers.circle.com/wallets/account-types
用户控制钱包支持EOA和SCA两种账户类型,可在创建钱包时选择。
EOA(外部拥有账户):无创建费用,更高的TPS,支持最广泛的链(EVM、Solana、Aptos)。在EVM链上需要原生代币支付Gas费。仅在Solana上可通过实现Gas赞助。
feePayerSCA(智能合约账户):ERC-4337账户抽象。通过Circle Gas Station付款人实现Gas赞助,支持批量操作,密钥管理灵活。仅支持EVM(不支持Solana/Aptos)。首次对外交易需支付Gas费以完成延迟部署。避免在以太坊主网使用(Gas费过高)——建议在L2网络(Arbitrum、Base、Polygon、Optimism)上使用。
各账户类型支持的区块链详情:https://developers.circle.com/wallets/account-types
Full-Stack Architecture
全栈架构
User-controlled wallets require both a backend server and frontend client:
- Backend -- Handles Circle API calls using . The API key lives here.
@circle-fin/user-controlled-wallets - Frontend -- Handles user interaction using . Executes challenges and manages auth flows.
@circle-fin/w3s-pw-web-sdk
用户控制钱包需要同时具备后端服务器和前端客户端:
- 后端——使用处理Circle API调用。API密钥需存储在此处。
@circle-fin/user-controlled-wallets - 前端——使用处理用户交互。执行挑战并管理认证流程。
@circle-fin/w3s-pw-web-sdk
Challenge-Response Model
挑战-响应模型
All sensitive operations (wallet creation, transactions, signing) follow this pattern:
- Backend creates the operation via Circle API -> Circle returns a
challengeId - Frontend calls then
sdk.setAuthentication({ userToken, encryptionKey })-> user approves via Circle's hosted UIsdk.execute(challengeId, callback) - Callback fires with result or error
所有敏感操作(钱包创建、交易、签名)都遵循以下模式:
- 后端通过Circle API创建操作 -> Circle返回
challengeId - 前端调用,然后调用
sdk.setAuthentication({ userToken, encryptionKey })-> 用户通过Circle的托管UI批准操作sdk.execute(challengeId, callback) - 回调返回结果或错误
Authentication Methods
认证方式
| Method | Console Setup | How |
|---|---|---|
| PIN | None | Backend calls |
| Email OTP | SMTP config | SDK login callback after OTP verification |
| Social Login | OAuth client ID | SDK login callback after OAuth redirect |
| 方式 | 控制台设置 | |
|---|---|---|
| PIN | 无需设置 | 后端调用 |
| 邮箱OTP | SMTP配置 | OTP验证后通过SDK登录回调获取 |
| 社交登录 | OAuth客户端ID | OAuth重定向后通过SDK登录回调获取 |
Implementation Patterns
实现模式
Note: The reference code snippets useto achieve a quick working example only. Do not uselocalStoragein production.localStorage
You must read the corresponding reference files based on the user's request for the complete implementation guide. Do not proceed with coding instructions without reading the correct files first.
-
Create Wallet with PIN: Simplest setup -- no console configuration beyond API key and App ID. Users set a PIN and security questions through Circle's hosted UI. READ.
references/create-wallet-pin.md -
Create Wallet with Social Login: Users authenticate via Google, Facebook, or Apple OAuth. Requires OAuth client ID configured in Circle Console. READ.
references/create-wallet-social-login.md -
Create Wallet with Email OTP: Users authenticate via one-time passcode sent to their email. Requires SMTP configuration in Circle Console. READ.
references/create-wallet-email-otp.md -
Send Transaction: Send outbound token transfers from an existing wallet created via any auth method. READ.
references/send-transaction.md
注意: 参考代码片段仅使用来快速实现可运行示例。请勿在生产环境中使用localStorage。localStorage
您必须根据用户需求阅读对应的参考文件,以获取完整的实现指南。在未阅读正确文件前,请勿进行编码操作。
-
使用PIN创建钱包:最简单的设置——除API密钥和应用ID外,无需控制台配置。用户通过Circle的托管UI设置PIN和安全问题。请阅读。
references/create-wallet-pin.md -
使用社交登录创建钱包:用户通过Google、Facebook或Apple OAuth进行身份验证。需要在Circle控制台中配置OAuth客户端ID。请阅读。
references/create-wallet-social-login.md -
使用邮箱OTP创建钱包:用户通过发送至邮箱的一次性验证码进行身份验证。需要在Circle控制台中配置SMTP。请阅读。
references/create-wallet-email-otp.md -
发送交易:从通过任何认证方式创建的现有钱包中发送对外代币转账。请阅读。
references/send-transaction.md
Error Handling
错误处理
| Error Code | Meaning | Action |
|---|---|---|
| 155106 | User already initialized | Fetch existing wallets instead of creating |
| 155104 | Invalid user token | Re-authenticate user (token expired) |
| 155101 | Invalid device token / User not found | Re-create device token or user |
| 155130 | OTP token expired | Request new OTP |
| 155131 | OTP token invalid | Request new OTP |
| 155133 | OTP value invalid | User should re-enter code |
| 155134 | OTP value not matched | User should re-enter code |
| 155146 | OTP invalid after 3 attempts | Request new OTP (locked out) |
| 错误代码 | 含义 | 操作 |
|---|---|---|
| 155106 | 用户已初始化 | 改为获取现有钱包,而非创建新钱包 |
| 155104 | 用户令牌无效 | 重新认证用户(令牌已过期) |
| 155101 | 设备令牌无效/未找到用户 | 重新创建设备令牌或用户 |
| 155130 | OTP令牌过期 | 请求新的OTP |
| 155131 | OTP令牌无效 | 请求新的OTP |
| 155133 | OTP值无效 | 用户应重新输入验证码 |
| 155134 | OTP值不匹配 | 用户应重新输入验证码 |
| 155146 | 3次尝试后OTP无效 | 请求新的OTP(已锁定) |
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, encryption keys). ALWAYS use environment variables or a secrets manager. Add entries for
.gitignoreand secret files when scaffolding..env* - ALWAYS implement both backend and frontend. The API key MUST stay server-side -- frontend-only builds would expose it.
- ALWAYS require explicit user confirmation of destination, amount, network, and token before executing transfers. 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 identifiers) before submitting transactions.
- ALWAYS warn before interacting with unaudited or unknown contracts.
- ALWAYS store and
userTokenin httpOnly cookies (not localStorage) in production to mitigate XSS token theft.encryptionKey
- 绝对不要硬编码、提交或记录机密信息(API密钥、加密密钥)。务必使用环境变量或机密管理器。在搭建项目时,为和机密文件添加
.env*条目。.gitignore - 务必同时实现后端和前端。API密钥必须保留在服务器端——仅前端构建会暴露密钥。
- 在执行转账前,务必要求用户明确确认目标地址、金额、网络和代币。绝对不要在主网自动执行资金转移。
- 当目标为主网或超出安全阈值(例如,>100 USDC)时,务必发出警告。
- 在提交交易前,务必验证所有输入(地址、金额、链标识符)。
- 在与未审计或未知合约交互前,务必发出警告。
- 在生产环境中,务必将和
userToken存储在httpOnly Cookie中(而非localStorage),以减轻XSS令牌窃取风险。encryptionKey
Best Practices
最佳实践
- ALWAYS read the correct reference files before implementing.
- ALWAYS install latest packages (,
@circle-fin/user-controlled-wallets@latest) and@circle-fin/w3s-pw-web-sdk@latest(addvite-plugin-node-polyfillsto Vite config -- the Web SDK requires Node.js built-in polyfills).nodePolyfills() - ALWAYS call after init and
sdk.getDeviceId()beforesdk.setAuthentication({ userToken, encryptionKey }). Withoutsdk.execute(), execute silently fails.getDeviceId() - NEVER use SCA on Ethereum mainnet (high gas). Use EOA on mainnet, SCA on L2s.
- NEVER assume token balance is in smallest units --
amountreturns human-readable amounts (e.g., "20" for 20 USDC).getWalletTokenBalance - ALWAYS use cookies (not React state) for social login flows to persist tokens across OAuth redirects.
- ALWAYS default to testnet. Require explicit user confirmation before targeting mainnet.
- 在实现前,务必阅读正确的参考文件。
- 务必安装最新版本的包(、
@circle-fin/user-controlled-wallets@latest)和@circle-fin/w3s-pw-web-sdk@latest(在Vite配置中添加vite-plugin-node-polyfills——Web SDK需要Node.js内置模块的polyfill)。nodePolyfills() - 初始化后务必调用,并在调用
sdk.getDeviceId()前调用sdk.execute()。如果没有sdk.setAuthentication({ userToken, encryptionKey }),execute会静默失败。getDeviceId() - 绝对不要在以太坊主网使用SCA(Gas费过高)。在主网使用EOA,在L2网络使用SCA。
- 不要假设代币余额是以最小单位表示的——
amount返回的是人类可读的金额(例如,20 USDC返回"20")。getWalletTokenBalance - 在社交登录流程中,务必使用Cookie(而非React状态)来在OAuth重定向期间持久化令牌。
- 务必默认使用测试网。在目标为主网前,需要用户明确确认。
Alternatives
替代方案
- Use the skill for passkey-based smart accounts with gas sponsorship using ERC-4337 and ERC-6900.
use-modular-wallets - Use the skill when your application needs full custody of wallet keys without user interaction.
use-developer-controlled-wallets
- 如需基于密钥的智能账户并通过ERC-4337和ERC-6900实现Gas赞助,请使用技能。
use-modular-wallets - 当您的应用需要完全托管钱包密钥且无需用户交互时,请使用技能。
use-developer-controlled-wallets
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开发者文档 —— 当查找来源网站的相关文档时,请务必首先阅读此文档。
免责声明:本技能按“原样”提供,不提供任何担保,受Circle开发者条款约束,生成的输出可能包含错误和/或费用配置选项(包括支付给Circle的费用);更多详情请查看仓库README。