Self 让用户使用零知识证明从护照/ID卡证明身份属性(年龄、国籍、人性)—— 不暴露个人数据。用户在 Self 移动应用中扫描其证件的 NFC 芯片,并与你的应用分享 zk 证明。
快速入门 (Next.js 离链)
1. 安装
npm install @selfxyz/qrcode @selfxyz/core
2. 前端 — QR 码组件
"use client";
import { SelfQRcodeWrapper, SelfAppBuilder } from "@selfxyz/qrcode";export default function VerifyIdentity({ userId }: { userId: string }) {
const selfApp = new SelfAppBuilder({
appName: "My App",
scope: "my-app-scope",
endpoint: "https://yourapp.com/api/verify",
endpointType: "https",
userId,
userIdType: "hex",
disclosures: {
minimumAge: 18,
},
}).build();
return (
console.log("Verified")}
type="websocket"
darkMode={false}
/>
);
}
3. 后端 — 验证端点
// app/api/verify/route.ts
import { SelfBackendVerifier, DefaultConfigStore } from "@selfxyz/core";export async function POST(req: Request) {
const { proof, publicSignals } = await req.json();
const verifier = new SelfBackendVerifier(
"my-app-scope", // 必须与前端 scope 匹配
"https://yourapp.com/api/verify", // 必须与前端 endpoint 匹配
true, // true = 接受模拟护照(仅开发用)
null, // allowedIds (null = 所有)
new DefaultConfigStore({
// 必须与前端 disclosures 匹配
minimumAge: 18,
})
);
const result = await verifier.verify(proof, publicSignals);
return Response.json({
verified: result.isValid,
nationality: result.credentialSubject?.nationality,
});
}
集成模式
| 模式 | 何时使用 | endpoint | endpointType |
|---|
| 离链 (后端) | Web应用、API、大多数情况 | 你的API URL | "https" 或 "https-staging" |
| 链上 (合约) | DeFi、代币门控、空投 | 合约地址(小写) | "celo" 或 "celo-staging" |
| 深链接 | 移动优先流程 | 你的API URL | "https" |
- 离链:最容易实现。证明发送到你后端,在服务器端验证。
- 链上:证明由 Celo 智能合约验证。继承
SelfVerificationRoot。用于无需信任/无许可场景。
- 深链接:面向移动用户——直接打开 Self 应用而非 QR 扫描。参见
references/frontend.md。
关键注意事项
- 配置匹配是强制的 — 前端
disclosures 必须与后端/合约验证配置完全匹配。不匹配的年龄阈值、国家列表或 OFAC 设置会导致静默失败。
- 合约地址必须是小写 — 前端
endpoint 中使用非校验和格式。使用 .toLowerCase()。
- 国家代码是 ISO 3字母 — 例如
"USA"、"IRN"、"PRK"。排除列表最多40个国家。
- 模拟护照 = 仅测试网 — 后端设置
mockPassport: true / 使用 "celo-staging" endpoint 类型。真实护照需要主网。创建模拟护照:打开 Self 应用,点击护照按钮 5次。模拟测试需要禁用 OFAC。
- 版本要求 —
@selfxyz/core >= 1.1.0-beta.1。
- 证明ID —
1 = 护照,2 = 生物识别ID卡。必须通过 allowedIds 映射明确允许。
- Scope 唯一性 — 链上,scope 与合约地址进行 Poseidon 哈希,防止跨合约证明重放。
- 端点必须可公开访问 — Self 应用直接将证明发送到你端点。本地开发使用 ngrok。
-
ScopeMismatch = scope/地址不匹配或非小写地址
-
Invalid 'to' Address = 错误的
endpointType(celo vs https)
-
InvalidIdentityCommitmentRoot = 真实护照在测试网(使用主网)
-
Invalid Config ID = 模拟护照在主网(使用测试网)
已部署合约 (Celo)
| 网络 | 地址 |
|---|
| 主网 Hub V2 | 0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF |
| Sepolia Hub V2 | 0x16ECBA51e18a4a7e61fdC417f0d47AFEeDfbed74 |
| Sepolia Staging Hub V2 | 0x68c931C9a534D37aa78094877F46fE46a49F1A51 |
参考资料
加载这些以获取更深入的集成详情:
references/frontend.md — SelfAppBuilder 完整配置,SelfQRcodeWrapper 属性,使用 getUniversalLink 的深链接,披露选项
references/backend.md — SelfBackendVerifier 构造函数详情,DefaultConfigStore vs InMemoryConfigStore,验证结果模式,动态配置
references/contracts.md — SelfVerificationRoot 继承模式,Hub V2 交互,setVerificationConfigV2,customVerificationHook,getConfigId,userDefinedData 模式
Self lets users prove identity attributes (age, nationality, humanity) from passports/ID cards using zero-knowledge proofs — no personal data exposed. Users scan their document's NFC chip in the Self mobile app and share a zk proof with your app.
Quick Start (Next.js Off-Chain)
1. Install
npm install @selfxyz/qrcode @selfxyz/core
2. Frontend — QR Code Component
"use client";
import { SelfQRcodeWrapper, SelfAppBuilder } from "@selfxyz/qrcode";export default function VerifyIdentity({ userId }: { userId: string }) {
const selfApp = new SelfAppBuilder({
appName: "My App",
scope: "my-app-scope",
endpoint: "https://yourapp.com/api/verify",
endpointType: "https",
userId,
userIdType: "hex",
disclosures: {
minimumAge: 18,
},
}).build();
return (
console.log("Verified")}
type="websocket"
darkMode={false}
/>
);
}
3. Backend — Verification Endpoint
// app/api/verify/route.ts
import { SelfBackendVerifier, DefaultConfigStore } from "@selfxyz/core";export async function POST(req: Request) {
const { proof, publicSignals } = await req.json();
const verifier = new SelfBackendVerifier(
"my-app-scope", // must match frontend scope
"https://yourapp.com/api/verify", // must match frontend endpoint
true, // true = accept mock passports (dev only)
null, // allowedIds (null = all)
new DefaultConfigStore({ // must match frontend disclosures
minimumAge: 18,
})
);
const result = await verifier.verify(proof, publicSignals);
return Response.json({
verified: result.isValid,
nationality: result.credentialSubject?.nationality,
});
}
Integration Patterns
| Pattern | When to Use | endpoint | endpointType |
|---|
| Off-chain (backend) | Web apps, APIs, most cases | Your API URL | "https" or "https-staging" |
| On-chain (contract) | DeFi, token gating, airdrops | Contract address (lowercase) | "celo" or "celo-staging" |
| Deep linking | Mobile-first flows | Your API URL | "https" |
- Off-chain: Fastest to implement. Proof sent to your backend, verified server-side.
- On-chain: Proof verified by Celo smart contract. Inherit
SelfVerificationRoot. Use for trustless/permissionless scenarios.
- Deep linking: For mobile users — opens Self app directly instead of QR scan. See
references/frontend.md.
Critical Gotchas
- Config matching is mandatory — Frontend
disclosures must EXACTLY match backend/contract verification config. Mismatched age thresholds, country lists, or OFAC settings cause silent failures.
- Contract addresses must be lowercase — Non-checksum format in frontend
endpoint. Use .toLowerCase().
- Country codes are ISO 3-letter — e.g.,
"USA", "IRN", "PRK". Max 40 countries in exclusion lists.
- Mock passports = testnet only — Set
mockPassport: true in backend / use "celo-staging" endpoint type. Real passports require mainnet. To create a mock passport: open Self app, tap the Passport button 5 times. Mock testing requires OFAC disabled.
- Version requirement —
@selfxyz/core >= 1.1.0-beta.1.
- Attestation IDs —
1 = Passport, 2 = Biometric ID Card. Must explicitly allow via allowedIds map.
- Scope uniqueness — On-chain, scope is Poseidon-hashed with contract address, preventing cross-contract proof replay.
- Endpoint must be publicly accessible — Self app sends proof directly to your endpoint. Use ngrok for local development.
- Common errors:
ScopeMismatch = scope/address mismatch or non-lowercase address. Invalid 'to' Address = wrong endpointType (celo vs https). InvalidIdentityCommitmentRoot = real passport on testnet (use mainnet). Invalid Config ID = mock passport on mainnet (use testnet).
Deployed Contracts (Celo)
| Network | Address |
|---|
| Mainnet Hub V2 | 0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF |
| Sepolia Hub V2 | 0x16ECBA51e18a4a7e61fdC417f0d47AFEeDfbed74 |
| Sepolia Staging Hub V2 | 0x68c931C9a534D37aa78094877F46fE46a49F1A51 |
References
Load these for deeper integration details:
references/frontend.md — SelfAppBuilder full config, SelfQRcodeWrapper props, deep linking with getUniversalLink, disclosure options
references/backend.md — SelfBackendVerifier constructor details, DefaultConfigStore vs InMemoryConfigStore, verification result schema, dynamic configs
references/contracts.md — SelfVerificationRoot inheritance pattern, Hub V2 interaction, setVerificationConfigV2, customVerificationHook, getConfigId, userDefinedData patterns