尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

如何用 OpenZeppelin Contracts MultiSignerERC7913 搭建 2-of-3 多签智能账户?

如何用 OpenZeppelin Contracts MultiSignerERC7913 搭建 2-of-3 多签智能账户? 如何用 OpenZeppelin Contracts MultiSignerERC7913 搭建 2-of-3 多签智能账户【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts如果你的需求是让一个智能账户必须得到 3 个签名者中至少 2 个的批准才能执行操作OpenZeppelin Contracts 的MultiSignerERC7913就是为此设计的签名验证合约。它会与 ERC-4337 智能账户基类Account组合使用账户继承MultiSignerERC7913后每个 UserOperation 的签名不再是单一私钥产生的而是abi.encode(signers, signatures)形式的多签结构验证逻辑会检查签名者是否已授权、签名本身是否有效以及签名数量是否达到阈值。下面按“定义账户合约 → 初始化 2-of-3 参数 → 编码多签 → 验证结果”的路径走一遍全部内容以 docs/modules/ROOT/pages/multisig.adoc 和 contracts/utils/cryptography/signers/MultiSignerERC7913.sol 为准。前提条件你使用的是 ERC-4337 智能账户体系账户合约继承 Account通过 EntryPoint 执行 UserOperation账户通常由工厂以最小化克隆minimal clone方式部署因此采用Initializable初始化设计initialize只能执行一次Solidity 版本参考文档示例pragma solidity ^0.8.27;MultiSignerERC7913.sol本身要求^0.8.26。ERC-7913 签名者格式先弄清 signer 是什么MultiSignerERC7913维护一个已授权签名者集合阈值机制要求至少threshold个有效签名才能批准操作。每个签名者是一个bytes对象遵循 ERC-7913 的verifier || key拼接格式ECDSA 签名者EOA直接就是 20 字节地址无需 verifierP256 签名者abi.encodePacked(p256Verifier, publicKeyX, publicKeyY)即 verifier 合约地址拼接公钥RSA 签名者abi.encodePacked(rsaVerifier, abi.encode(publicKeyE, publicKeyN))。长度是硬约束_addSigners要求每个 signer 至少 20 字节否则 revertMultiSignerERC7913InvalidSigner见 MultiSignerERC7913.sol。此外源码注释明确提醒合约本身不会校验 signer 是否“受控”address(0)、账户自身地址可能导致递归验证、以及如0x04身份预编译这类对任意isValidSignature都返回 ERC-1271 魔值的地址都可能破坏多签的安全性集成方在添加前必须自行确认。定义多签账户合约文档给出的账户合约示例如下来自 multisig.adoc// contracts/MyAccountMultiSigner.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; import {Account} from openzeppelin/contracts/account/Account.sol; import {EIP712} from openzeppelin/contracts/utils/cryptography/EIP712.sol; import {ERC721Holder} from openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol; import {ERC1155Holder} from openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol; import {ERC7739} from openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol; import {ERC7821} from openzeppelin/contracts/account/extensions/draft-ERC7821.sol; import {Initializable} from openzeppelin/contracts/proxy/utils/Initializable.sol; import {MultiSignerERC7913} from openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol; contract MyAccountMultiSigner is Account, EIP712, MultiSignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder, Initializable { constructor() EIP712(MyAccountMultiSigner, 1) {} function initialize(bytes[] memory signers, uint64 threshold) public initializer { _addSigners(signers); _setThreshold(threshold); } function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _addSigners(signers); } function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf { _removeSigners(signers); } function setThreshold(uint64 threshold) public onlyEntryPointOrSelf { _setThreshold(threshold); } /// dev Allows the entry point as an authorized executor. function _erc7821AuthorizedExecutor( address caller, bytes32 mode, bytes calldata executionData ) internal view virtual override returns (bool) { return caller address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData); } }几点需要留意initialize的threshold参数这里写成uint64。文档示例原文写作uint256但MultiSignerERC7913._setThreshold的签名是uint64见 MultiSignerERC7913.sol 及该文件头部注释中的用法示例因此按uint64声明才能通过编译。仓库测试用的 mockAccountMultiSignerMock的继承组合与上面一致Account, MultiSignerERC7913, ERC7739, ERC7821, ERC721Holder, ERC1155Holder见 contracts/mocks/account/AccountMock.sol。ERC7739提供防御性重哈希防止同一签名者在多个账户间重放签名accounts.adoc 明确推荐使用。文档警告账户若一直未初始化会处于不可用状态因为没有任何公钥/签名者与它关联。若需要签名者权重不同的治理结构如不同投票权可选的替代方案是文档同页介绍的MultiSignerERC7913Weighted本文的 2-of-3 等权场景用MultiSignerERC7913即可。初始化 2-of-3定义三个签名者并设置阈值为 2文档给出的 2-of-3 设置示例如下alice是 EOA 地址p256Verifier、rsaVerifier是已部署的 ERC-7913 verifier 合约地址bobP256PublicKeyX/Y、charlieRSAPublicKeyE/N是相应公钥分量——实际部署时替换为你自己的值// Example setup code function setupMultisigAccount() external { // Create signers using different types of keys bytes memory ecdsaSigner alice; // EOA address (20 bytes) // P256 signer with format: verifier || pubKey bytes memory p256Signer abi.encodePacked( p256Verifier, bobP256PublicKeyX, bobP256PublicKeyY ); // RSA signer with format: verifier || pubKey bytes memory rsaSigner abi.encodePacked( rsaVerifier, abi.encode(charlieRSAPublicKeyE, charlieRSAPublicKeyN) ); // Create array of signers bytes[] memory signers new bytes[](3); signers[0] ecdsaSigner; signers[1] p256Signer; signers[2] rsaSigner; // Set threshold to 2 (2-of-3 multisig) uint256 threshold 2; // Initialize the account myMultisigAccount.initialize(signers, threshold); }注意initialize内部先_addSigners再_setThreshold而_setThreshold末尾会调用_validateReachableThreshold当前签名者总数必须大于等于阈值否则 revertMultiSignerERC7913UnreachableThreshold。这保证了一个 2-of-3 账户不会因为误配置如只加 1 个 signer 却设阈值 2变成无法操作的账户。另外_setThreshold要求阈值非零0会 revertMultiSignerERC7913ZeroThreshold。部署后的签名者管理通过addSigners、removeSigners、setThreshold完成三者都受onlyEntryPointOrSelf限制——只能通过 EntryPoint 发起的 UserOperation即同样需要多签批准或账户自身调用不能由外部地址直接执行。移除签名者后同样会触发_validateReachableThreshold避免把账户锁死。编码多签signers 与 signatures 如何组合对 UserOperation 做验证时signature字段不再是单份签名而是abi.encode( bytes[] signers, // Array of signers sorted by keccak256 bytes[] signatures // Array of signatures corresponding to each signer )其中signers数组只包含本次实际参与签名的签名者2-of-3 场景下通常是 2 个signatures数组与signers一一对应文档要求signers按keccak256(signer)升序排列、signatures跟随相同顺序以避免重复签名者并利用验证的 gas 优化。源码注释中给出的编码示意MultiSignerERC7913.sol// Encode signers (verifier || key) bytes memory signer1 abi.encodePacked(verifier1, key1); bytes memory signer2 abi.encodePacked(verifier2, key2); // Order signers by their id if (keccak256(signer1) keccak256(signer2)) { (signer1, signer2) (signer2, signer1); (signature1, signature2) (signature2, signature1); } // Assign ordered signers and signatures bytes[] memory signers new bytes[](2); bytes[] memory signatures new bytes[](2); signers[0] signer1; signatures[0] signature1; signers[1] signer2; signatures[1] signature2; // Encode the multi signature bytes memory signature abi.encode(signers, signatures);仓库测试中的MultiERC7913SigningKey辅助类按同样方式工作构造时按keccak256排序 signersign时编码为abi.encode([bytes[], bytes[]], [signers, signatures])见 test/helpers/signers.js。验证入口是_rawSignatureValidation(hash, signature)先解码多签结构再依次检查签名者数量是否达到threshold、每个 signer 是否已授权isSigner、以及各签名对哈希是否有效。外层编码不合法时返回false而不是 revert这与 ERC-4337 的SIG_VALIDATION_FAILED语义一致。验证账户搭建是否成功搭建完成后可以用以下只读接口逐项核对对应 multisig.adoc 与源码getSignerCount()应返回 3getSigners(0, type(uint64).max)返回全部三个 signer注意文档提示该函数会把数据拷贝到内存适合免 gas 的 view 查询放在状态变更函数里大片段可能因 gas 问题不可调用isSigner(bytes memory signer)对已注册的 signer 返回true未注册的返回falsethreshold()应返回2。签名验证层面仓库测试文件 test/account/AccountMultiSigner.test.js 覆盖了 2 阈值场景[signerECDSA1.address, signerECDSA2.address], 2以及混合签名者场景ECDSA P256 RSA、阈值 2其中“Signature validation”一组用例可以直接作为验收标准已授权签名者的有效多签_rawSignatureValidation返回true签名者中包含未授权地址返回false某个签名本身无效对错误消息签名返回falsesigners与signatures数组长度不一致返回falsesigners中出现重复签名者返回false。此外账户实现了 ERC-1271isValidSignature(hash, signature)对合法多签返回0x1626ba7eIERC1271.isValidSignature.selector这也是 accounts.adoc 描述的启用方式。管理操作的链上痕迹则通过事件确认添加签名者发ERC7913SignerAdded移除发ERC7913SignerRemoved阈值变更发ERC7913ThresholdSet。边界与常见错误配置或运行中遇到 revert 时对照源码中的自定义错误MultiSignerERC7913.sol错误触发条件MultiSignerERC7913InvalidSignersigner 短于 20 字节MultiSignerERC7913AlreadyExists添加的 signer 已存在MultiSignerERC7913NonexistentSigner移除的 signer 不在集合中MultiSignerERC7913ZeroThreshold设置阈值为 0MultiSignerERC7913UnreachableThreshold当前 signer 数量不足以达到阈值测试文件 test/account/AccountMultiSigner.test.js 的“Signer management”用例展示了这些错误的实际触发方式例如阈值 1、两个 signer 的账户中连续移除两个 signer第二次移除剩余 0 个会以MultiSignerERC7913UnreachableThreshold(0, 1)revert。最后两条限制值得写进你的部署清单自定义基于多签合约的逻辑时文档强调必须保证阈值始终可达——_validateReachableThreshold只在添加/移除 signer、设置阈值时自动执行任何绕过内部函数的自定义路径都要自行维持这一不变式账户未调用initialize之前不可用addSigners/removeSigners/setThreshold只能通过 EntryPoint即多签批准的 UserOperation或账户自身触发因此初始化时给出的 signer 集合要慎重后续变更本身也要 2-of-3 批准。【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表