拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Sismo Badges 协议智能合约架构与开发实战:从 AttestationsRegistry 到自定义 Attester

区块链Web3【免费下载链接】sismo-badgesContracts of the Sismo Badge Minting Protocol项目地址https://gitcode.com/gh_mirrors/si/sismo-badges点击查看免费下载本文是一份面向 Solidity 开发者的 Sismo Badge 铸造协议Sismo Badge Minting Protocol技术指南。文章以仓库根目录的 README.md 为骨架深入contracts/目录下的核心合约实现系统讲解三大核心合约AttestationsRegistry、Attester、Badges的设计原理、官方 Attester 实现Hydra S1 系列并给出从零开发一个新 Attester 的完整实战路径。读完本文你将理解 Sismo 协议中证明Attestation— 徽章Badge的底层数据流并具备在本地编译、测试、部署以及编写自定义 Attester 合约的实操能力。上图docs/schema1.png展示了 Sismo Attestation Protocol 的整体架构用户如 John Doe向多个 Attester 发起声明验证请求各 Attester 将生成的 Attestation 写入对应的 Attestation Collection Slots最终汇聚为 Sismo Attestations State。协议概览三大核心合约的分工仓库 README.md 明确指出本仓库包含 Sismo Protocol 的智能合约其中三个核心合约共同构成了协议的骨架AttestationsRegistrycontracts/core/AttestationsRegistry.sol存储所有证明的记录中心。它由治理governance拥有治理负责授权/取消授权authorize/unauthorize发行者issuers在注册表中写入记录。Attestercontracts/core/Attester.sol必须被所有 Attester 继承的标准抽象合约。Attester 是证明的发行者负责验证用户请求并构建将被记录到注册表中的证明。Badgescontracts/core/Badges.sol读取注册表提供证明的无状态Stateless、不可转移Non TransferableToken 视图标准为 ERC1155。此外仓库还提供了位于 contracts/attesters/ 的官方 Attester 实现README 特别列出两类HydraS1SimpleAttesterHydraS1SimpleAttester.sol基于 Hydra S1 Proving Scheme 的 ZK零知识Attester引入 nullifier 概念。用户必须随请求提交 ZK Proof 才能生成证明。HydraS1AccountboundAttesterHydraS1AccountboundAttester.solHydra S1 Simple Attester 的 Accountbound账户绑定版本用户可以按意愿更新证明的存储位置。需要说明的是README 提到的证明记录后用户获得徽章这一规则正是通过下文将要展开的recordAttestations与_triggerBadgeTransferEvent机制实现的。数据模型Request、Claim 与 Attestation 结构在深入合约之前先理解协议的数据结构。它们统一定义在 contracts/core/libs/Structs.sol 中是所有合约共享的基础类型Request用户发起的证明请求由一组Claim[]和一个destination组成。destination是最终接收证明的目标地址。注意注释中隐含attester与chainId字段由调用上下文确定。Claim用户声明包含groupId用户声称自己属于的账户组、claimedValue声称在该组中的值如分数以及extraData任意字节Attester 可能用它来校验声明或生成特定证明。AttestationAttester 构建并写入注册表的证明记录。包含collectionId证明集合 ID注册表中的标识、owner证明所有者、issuer创建或最后更新记录的合约、value证明值、timestampAttester 选择的生效时间可能与记录时间不同例如 NFT 所有权证明可能是两个月前的数据今天才记录和extraData。AttestationData注册表中实际存储的证明数据形态上下文隐含collectionId与owner仅存储issuer、value、timestamp、extraData四个字段。从 AttestationsRegistry.sol 的recordAttestations实现可以看到注册表使用mapping(uint256 mapping(address AttestationData))这类键值对collectionId owner AttestationData存储数据每次记录都会覆盖旧值即创建新证明或覆盖已有证明。核心合约一AttestationsRegistry —— 证明的存储与授权存储与权限模型AttestationsRegistry.sol 的合约注释说明了它的定位Sismo 的主合约将所有已记录的证明存储在证明集合collections中只有被授权的证明发行者才能在其中记录。合约头声明uint8 public constant IMPLEMENTATION_VERSION 3并通过继承AttestationsRegistryState、IAttestationsRegistry与AttestationsRegistryConfigLogiccontracts/core/libs/attestations-registry/AttestationsRegistryConfigLogic.sol获得状态存储与授权逻辑。它还包含一个不可变的IBadges BADGES引用指向无状态 ERC1155 徽章合约用于触发链上事件。从构造函数签名L38-L41可以看出部署时需传入两个参数参数含义owner合约所有者拥有授权/取消授权证明发行者的权限badgesAddress无状态 ERC1155 Badges 合约地址合约采用可升级代理模式initialize(address ownerAddress)使用reinitializer(IMPLEMENTATION_VERSION)修饰符以保证通过代理升级时能够重新初始化新增模块详见 L48-L53。记录与删除recordAttestations / deleteAttestationsrecordAttestations(Attestation[] calldata attestations)L59-L84是授权发行者调用的主函数执行流程如下取出调用者issuer _msgSender()对每一条证明检查_isAuthorized(issuer, collectionId)未授权则revert IssuerNotAuthorized(issuer, collectionId)读取该collectionId owner组合的旧值previousAttestationValue将新的AttestationData写入存储调用_triggerBadgeTransferEvent触发徽章转移事件发出AttestationRecorded事件。deleteAttestations(owners, collectionIds)L91-L119执行删除要求两个数组长度相等否则revert OwnersAndCollectionIdsLengthMismatch。删除同样校验授权并将删除后的值视为 0 触发转移事件随后发出AttestationDeleted。查询接口合约提供了丰富的只读查询函数全部带external view修饰hasAttestation(collectionId, owner)返回布尔值判断值是否非 0getAttestationData/getAttestationDataTuple返回AttestationData结构或其元组形式(issuer, value, timestamp, extraData)getAttestationValue/getAttestationIssuer/getAttestationTimestamp/getAttestationExtraData分别返回单个字段getAttestationDataBatch/getAttestationValueBatch批量查询版本。Shadow Mint徽章事件如何被链下应用捕获注册表并不真正铸造/转移 ERC1155 Token而是通过_triggerBadgeTransferEventL247-L261从 Badges 合约发出TransferSingle事件实现影子铸造shadow mint/影子销毁shadow burnbool isGreaterValue newValue previousValue; address operator address(this); address from isGreaterValue ? address(0) : owner; address to isGreaterValue ? owner : address(0); uint256 value isGreaterValue ? newValue - previousValue : previousValue - newValue; BADGES.triggerTransferEvent(operator, from, to, badgeTokenId, value);当值增大时from address(0)、to owner模拟铸造事件值减少时方向相反模拟销毁事件。这一设计使得 OpenSea 等依赖事件的链下应用能够捕捉到徽章的影子铸造而无需真实转移 Token注释见 L243-L245。核心合约二Attester —— 标准抽象基类两个主入口generateAttestations 与 deleteAttestationsAttester.sol 是所有 Attester 推荐的继承基类合约头注释强调想要在 Sismo 协议中获得授权即拥有注册表写入权限的 Attester 都应实现这个抽象合约且两个主入口函数不应被覆写除非你非常清楚自己在做什么。generateAttestations(request, proofData)L49-L70的完整调用链如下_verifyRequest(request, proofData)—— 用 proof 校验用户请求强制实现buildAttestations(request, proofData)—— 从请求构建实际证明强制实现_beforeRecordAttestations(request, proofData)—— 记录前钩子可选ATTESTATIONS_REGISTRY.recordAttestations(attestations)—— 写入注册表_afterRecordAttestations(attestations)—— 记录后钩子可选对每条证明发出AttestationGenerated事件并返回。deleteAttestations(collectionIds, attestationsOwner, proofData)L102-L149先根据collectionIds与attestationsOwner从注册表拉取现有证明组装成数组然后依次执行_verifyAttestationsDeletionRequest默认直接revert AttestationDeletionNotImplemented见 L186-L191、_beforeDeleteAttestations、ATTESTATIONS_REGISTRY.deleteAttestations(...)、_afterDeleteAttestations最后逐个发出AttestationDeleted事件。此外还有便捷函数mintBadges(request, proofData)L78-L93在调用generateAttestations后把结果拆解为(owner, collectionIds, values)三元组返回方便前端直接读取徽章信息。子类必须/可选实现的函数一览函数类型说明_verifyRequest(request, proofData)必须内部函数实现用户请求与 proof 的校验逻辑buildAttestations(request, proofData)必须公开 view 函数构建将被记录的证明数组_beforeRecordAttestations(request, proofData)可选记录前钩子可用于 nullifier 检查等前置逻辑_afterRecordAttestations(attestations)可选记录后钩子_verifyAttestationsDeletionRequest(...)可选默认 revert覆写后可启用删除功能_beforeDeleteAttestations/_afterDeleteAttestations可选删除前后钩子构造函数接收attestationsRegistryAddress并存入不可变变量ATTESTATIONS_REGISTRY同时提供getAttestationRegistry()访问器。核心合约三Badges —— 无状态的不可转移 ERC1155Badges.sol 是协议的视图层。其核心设计是不存储任何余额余额完全由注册表实时计算得出。合约头注释直接说明无状态、不可转移的 ERC1155 合约从证明的值读取余额关联的证明注册表从该合约触发 TransferSingle 事件使徽章的影子铸造与销毁能被链下平台捕获。关键实现细节balanceOf(account, id)L62-L67直接转发到_attestationsRegistry.getAttestationValue(id, account)因此attestationCollectionId badgeId用户的徽章余额恒等于底层证明的值。不可转移setApprovalForAll、isApprovedForAll以及内部_beforeTokenTransfer全部revert BadgesNonTransferrable()见 L72-L84 与 L188-L197从机制上杜绝徽章的转售与流转。triggerTransferEvent(operator, from, to, id, value)L95-L103仅限拥有EVENT_TRIGGERER_ROLE即注册表地址的角色调用直接emit TransferSingle(...)这就是注册表影子铸造事件的最终出口。管理函数setAttestationsRegistry、setUri均受DEFAULT_ADMIN_ROLE保护getAttestationsRegistry、getBadgeIssuer、getBadgeTimestamp、getBadgeExtraData等为只读查询。构造函数接收(uri, owner)其中注释表明owner即 Sismo Frontend Contract前端合约并同样使用reinitializer(IMPLEMENTATION_VERSION)完成代理初始化。官方 Attester 实战解析Hydra S1 系列HydraS1SimpleAttesterZK、分数制与 nullifierHydraS1SimpleAttester.sol 是 README 推荐的实现上述函数的优秀示例。合约注释总结了它的四个特性Zero Knowledge零知识无法从一条证明反推出生成其底层 proof 的源账户Non Strict scores分数制用户若能生成最大值 100 的证明也能生成任意小于 100 的证明Nullified抗重放每个源账户在每个 claim 下只有一个 nullifier即每个源账户每个 claim 至多一条证明。其记法与 Semaphore/Tornado Cash 对齐nullifier hash(sourceSecret, externalNullifier)Renewable可续期只要证明的目标地址不变nullifier 可重复使用从而支持用户续期证明。构造函数需要六个参数attestationsRegistryAddress注册表地址、hydraS1VerifierAddressZK Snark Hydra-S1 验证器合约、availableRootsRegistryAddress存储可用账户组根哈希的注册表、commitmentMapperAddresscommitment mapper 公钥注册表、collectionIdFirst与collectionIdLast该 Attester 获准写入的证明集合 ID 区间对应 README 中部署后需被授权写入注册表的要求。两个强制函数的实现很有代表性_verifyRequestL104-L116用abi.decode从proofData还原出HydraS1ProofData与HydraS1ProofInput先从请求还原HydraS1Claim再调用_validateInput(claim, snarkInput)校验 proof 与声明一致、_verifyProof(snarkProof)校验 proof 本身有效性。buildAttestationsL122-L149集合 ID 计算为AUTHORIZED_COLLECTION_ID_FIRST groupIndex超出AUTHORIZED_COLLECTION_ID_LAST则revert CollectionIdOutOfBound从 proof 提取nullifier编码进extraDataissuer为合约自身value为用户声明的claimedValue。该 Attester 还覆写了_beforeRecordAttestations钩子L161-L174若 nullifier 已有目标地址且与本次request.destination不同则revert NullifierUsed(nullifier)否则记录 nullifier 与目标地址的映射这正对应nullifier 只能被同一目的地复用的可续期语义。HydraS1AccountboundAttester账户绑定与冷却期HydraS1AccountboundAttester.sol 继承了HydraS1SimpleAttester与 OpenZeppelin 的Ownable在保留 ZK、分数制、nullifier 与可续期特性的基础上新增Accountbound可选加入带冷却期能力注释见 L45-L56合约所有者可为某个 group 设置cooldownDuration冷却时长从而为该组激活账户绑定特性用户可通过提供新的 Hydra-S1 ZK Proof 更新证明的目标地址即证明绑定源账户、存储在可更新的目标账户上删除或迁移到新目标地址时nullifier 进入冷却期防止频繁迁移冷却时长为 0 的组不启用账户绑定证明不可迁移但迁移会留下可观察的关联他人可得知新旧目标地址由同一 nullifier 产生。实现层面它通过三个映射存储状态L86-L92_cooldownDurations每个 groupIndex 的冷却时长、_nullifiersCooldownStartnullifier 冷却起点、_nullifiersBurnCountnullifier 的销毁计数。buildAttestations覆写为把 nullifier 与burnCount一起编码进extraDataL152-L165_beforeRecordAttestations则在迁移场景下检查冷却时长为 0 则revert CooldownDurationNotSetForGroupIndex冷却中则revert NullifierOnCooldown并删除旧目标地址上的证明、把 nullifier 置入冷却并递增 burnCountL176-L210。对外还提供getNullifierBurnCount、getNullifierCooldownStart等查询函数。其他相关合约除 Hydra S1 外仓库还包含Pythia1SimpleAttestercontracts/attesters/pythia-1/Pythia1SimpleAttester.sol另一款官方 Attester 实现位于attesters/pythia-1/目录Frontcontracts/core/Front.sol前端路由合约位于代理之后将证明请求转发到目标 Attester并可执行附加动作如为早期用户生成早期用户证明AddressesProvidercontracts/core/utils/AddressesProvider.sol与SismoLibcontracts/libs/SismoLib.sol地址管理与合约集成辅助库。环境搭建与本地开发安装、编译、测试与部署README 的 Usage 章节给出了完整的开发命令。以下命令均定义于 package.json 的scripts字段# 安装依赖Hardhat、OpenZeppelin、sismo-core/hydra-s1 等 yarn # 编译合约等价于 SKIP_LOADtrue hardhat compile yarn compile # 运行全部测试等价于 hardhat test yarn test # 打印合约存储布局等价于 hardhat print-storage-layout yarn storage-layout本地链部署需要两个终端窗口对应 README 的说明# 终端 1启动本地 Hardhat 节点等价于 hardhat node yarn chain # 终端 2部署完整协议到本地链 yarn deploy:localdeploy:local实际执行rm -rf deployments/local hardhat deploy-full-local --network local其中deploy-full-local任务位于 tasks/deploy-tasks/full/local/deploy-full-local.task.ts。从 hardhat.config.ts 可以看到Solidity 编译器版本为0.8.14开启优化器runs: 200默认网络为hardhat本地网络默认监听localhost:8545、chainId 为31337均可用环境变量LOCAL_HOSTNAME、LOCAL_PORT、LOCAL_CHAIN_ID覆盖同时还配置了 mainnet、polygon、gnosis、goerli 测试网等远端网络。yarn storage-layout依赖hardhat-storage-layout插件package.json 中的依赖项这也是 Hydra S1 合约中大量_placeHolders*占位数组存在的原因——通过预留存储槽位保证未来升级时存储布局兼容例如 HydraS1SimpleAttester 的uint256[19] private _placeHoldersHydraS1Simple。仓库测试覆盖较为完整可参考注册表单元测试test/unit/core/attestations-registry/attestations-registry.test.tsBadges 单元测试test/unit/core/badges.test.tsHydra S1 Simple Attester 测试test/unit/attesters/hydra-s1/hydra-s1-simple-attester.test.tsHydra S1 Accountbound Attester 测试test/unit/attesters/hydra-s1/hydra-s1-accountbound-attester.test.ts端到端测试test/e2e/e2e.test.ts此外tasks/目录提供了大量管理任务例如授权范围管理任务 tasks/helpers/authorizations/attestations-registry-authorize-range.task.ts对应 README 中Attester 需被授权写入集合区间的运维需求与代理升级任务 tasks/helpers/proxy/upgrade-proxy.task.ts。创建新 Attester继承、实现与验证README 给出了开发新 Attester 的明确指引继承core/Attester.sol抽象合约并实现以下函数_verifyRequest(request, proofData)实现用户请求与用户提交 proof 之间的校验buildAttestations(request, proofData)根据已校验的用户请求构建将被记录的证明。可选实现的钩子函数_beforeRecordAttestations(request, proofData)_afterRecordAttestations(request, proofData)从源码来看一个完整的自定义 Attester 骨架如下对照 Attester.sol 的强制函数签名// SPDX-License-Identifier: MIT pragma solidity ^0.8.14; import {Attester, IAttestationsRegistry} from ./core/Attester.sol; import {Request, Attestation} from ./core/libs/Structs.sol; contract MyAttester is Attester { constructor(address attestationsRegistryAddress) Attester(attestationsRegistryAddress) {} // 强制实现校验用户请求与 proof function _verifyRequest(Request calldata request, bytes calldata proofData) internal virtual override { // 在这里实现业务校验逻辑 } // 强制实现构建待记录的证明 function buildAttestations(Request calldata request, bytes calldata proofData) public view virtual override returns (Attestation[] memory) { // 在这里根据 request 构建 Attestation 数组 } // 可选记录前钩子如 nullifier 检查 function _beforeRecordAttestations(Request calldata request, bytes calldata proofData) internal virtual override {} // 可选记录后钩子 function _afterRecordAttestations(Attestation[] memory attestations) internal virtual override {} }实现要点与参考参考实现README 明确推荐以 HydraS1SimpleAttester.sol 为范本。它演示了如何解析 proof、如何计算collectionId、如何将 nullifier 写入extraData以及如何通过_beforeRecordAttestations钩子实现幂等与防重放。授权前提从 AttestationsRegistry.sol 的recordAttestations可见Attester 合约部署后还必须由治理在注册表中授权其写入对应collectionId区间IssuerNotAuthorizedrevert 即此机制否则调用会失败。删除功能默认继承的_verifyAttestationsDeletionRequest会直接 revertAttester.sol如需支持删除须覆写该方法否则调用deleteAttestations会抛AttestationDeletionNotImplemented。测试验证参考 test/unit/attesters/hydra-s1/hydra-s1-simple-attester.test.ts 与 test/unit/attesters/hydra-s1/hydra-s1-accountbound-attester.test.ts 编写单元测试覆盖请求校验、证明构建、nullifier 防重放等场景再通过yarn test运行。部署与授权流程可参照 tasks/deploy-tasks/ 下的部署任务组织自己的部署脚本并在部署后通过 tasks/helpers/authorizations/attestations-registry-authorize-range.task.ts 这类授权任务完成集合区间授权。总结Sismo Badges 协议以注册表存储证明、Attester 发行证明、Badges 无状态展示证明的三层架构实现了可验证、抗重放、可续期的链上徽章系统AttestationsRegistry通过治理授权与TransferSingle影子事件保证数据权威性与链下可观测性Attester抽象基类以两个强制函数 一组可选钩子的简洁契约承载了无限的自定义扩展空间Badges以零存储的 ERC1155 实现不可转移的徽章视图。无论是理解协议原理还是基于 Attester.sol 开发新的 ZK 或非 ZK Attester本文提供的源码路径、数据流分析与本地开发命令都足以支撑你完成从阅读到落地的完整闭环。赞分享区块链Web3【免费下载链接】sismo-badgesContracts of the Sismo Badge Minting Protocol项目地址https://gitcode.com/gh_mirrors/si/sismo-badges点击查看免费下载相关推荐MiMo-VL-7B-SFT-2508架构深度剖析从ViT编码器到MORL强化学习的技术突破MiMo VL 7B SFT 2508架构深度剖析从ViT编码器到MORL强化学习的技术突破 小米MiMo VL 7B SFT 2508是一款革命性的视觉语言Sismo Badge Minting Protocol开发者教程如何编写自定义Attester测试的完整指南Sismo Badge Minting Protocol开发者教程如何编写自定义Attester测试的完整指南 Sismo Badge Minting Pro区块链Web3Apache Thrift TProtocol详解自定义协议开发指南Apache Thrift TProtocol详解自定义协议开发指南 协议基础从二进制到自定义实现 Apache Thrift作为跨语言RPC框架其核心能后端RPC框架序列化代码生成上一篇如何通过Spinning Up掌握多智能体协作策略深度强化学习终极指南下一篇SiYuan v3.5.4 版本详解导出体系、编辑器交互与同步安全的多点增强创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门