EIPs 仓库 EIP-3267 合约中的 ERC1155 多代币标准实现解析:从接口定义到 WithTotals 扩展

EIPs 仓库 EIP-3267 合约中的 ERC1155 多代币标准实现解析:从接口定义到 WithTotals 扩展 EIPs 仓库 EIP-3267 合约中的 ERC1155 多代币标准实现解析从接口定义到 WithTotals 扩展【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs本篇技术指南以 assets/eip-3267/contracts/ERC1155/README.md 为骨架系统解析 EIP-3267科学薪资 / Salary 提案合约集中自带的一套完整 ERC1155 多代币Multi Token实现。你将掌握该实现中IERC1155与IERC1155TokenReceiver两个接口的分工、ERC1155基础合约的存储与安全转账机制、ERC1155WithTotals对总供应量的扩展以及它们在 EIP-3267 的锁仓与薪资合约中的真实调用方式可直接对照仓库源码逐行验证。一、文档定位EIP-3267 合约集内的 ERC1155 模块在 assets/eip-3267/contracts/README.md 中ERC1155/目录被列为 EIP-3267 draft 合约源码的一部分与BaseLock.sol、BaseSalary.sol、SalaryWithDAO.sol等业务合约并列。该目录的 README.md 说明了模块的三个核心要点目录内所有接口与合约都关联于ERC1155 Multi Token Standard即 EIP-1155 多代币标准。EIP 由两个承担不同角色的接口组成IERC1155与IERC1155TokenReceiver。只有IERC1155是一个合约达到 ERC1155 合规所必需的基础功能实现在ERC1155合约中。也就是说这一模块并非业务代码而是为 EIP-3267 的上层合约尤其是锁仓与薪资治理中使用的“担保物 / 代币”提供标准化的多代币基础设施其具体业务侧调用证据见后文第五节。二、接口层IERC1155与IERC1155TokenReceiver的职责分工1.IERC1155合规的必需接口源码位于 IERC1155.sol基于pragma solidity ^0.7.1继承 OpenZeppelin 的IERC165。它声明了 ERC1155 标准的 4 个事件与 6 个函数成员签名说明TransferSingle(operator, from, to, id, value)单种代币类型转账事件TransferBatch(operator, from, to, ids, values)批量转账事件ApprovalForAll(owner, operator, approved)全量授权事件URI(value, id)代币元数据 URI 变更事件balanceOf(owner, id) → uint256查询某账户某代币类型余额balanceOfBatch(owners, ids) → uint256[]批量查询余额setApprovalForAll(operator, approved)将操作权授予/撤销给 operatorisApprovedForAll(owner, operator) → bool查询全量授权状态safeTransferFrom(from, to, id, value, data)安全单笔转账safeBatchTransferFrom(from, to, ids, values, data)安全批量转账注意接口中balanceOf/balanceOfBatch被声明为view virtual而safeTransferFrom/safeBatchTransferFrom为external virtual这与后续实现合约中的public virtual override写法兼容。2.IERC1155TokenReceiver接收方钩子接口源码位于 IERC1155TokenReceiver.sol同样基于pragma solidity ^0.7.1并继承IERC165。它定义了两个回调函数onERC1155Received(operator, from, id, value, data)在safeTransferFrom末尾、余额更新后被调用接受转账必须返回魔术值bytes4(keccak256(onERC1155Received(address,address,uint256,uint256,bytes)))即0xf23a6e61或其自身的函数选择器。onERC1155BatchReceived(operator, from, ids, values, data)在safeBatchTransferFrom末尾被调用接受转账必须返回bytes4(keccak256(onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)))即0xbc197c81。文档特别强调该接口不是合规所必需的——普通 EOA 或无需接收钩子的合约可以完全不实现它只有“接收代币的合约”才需要实现以保证安全转账不失败。三、基础实现ERC1155状态、接口注册与安全转账核心实现位于 ERC1155.sol编译版本声明为pragma solidity 0.6.0 0.8.0采用 OpenZeppelin 3.x 风格SafeMath、Address、Context、ERC165并注明“Originally based on code by Enjin”。1. 存储布局与接口注册mapping (uint256 mapping(address uint256)) internal _balances; mapping (address mapping(address bool)) internal _operatorApprovals; string private _uri;_balances[id][account]以“代币类型 ID → 账户 → 余额”的双层映射存储这正是 ERC1155 与 ERC20/ERC721 “一类一合约”的本质区别——多类代币共享同一份余额账本。_operatorApprovals全量授权operator 模式区别于 ERC20 的按额度授权。_uri所有代币类型共用的元数据 URI 模板。构造函数接收string memory uri_调用_setURI后通过_registerInterface注册两个 ERC165 接口 ID_INTERFACE_ID_ERC1155 0xd9b67a26由六个函数选择器 XOR 得出0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^ 0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6。_INTERFACE_ID_ERC1155_METADATA_URI 0x0e89341c即uri(uint256)的选择器。这使得任何调用方可通过 ERC165 的supportsInterface静态验证合约是否合规。2. URI 的{id}替换机制uri(uint256)实现返回统一的_uri模板依赖 EIP-1155 元数据中定义的“代币类型 ID 替换”机制客户端需将模板中的{id}子串替换为实际的代币类型 ID。例如模板https://token-cdn-domain/{id}.json对代币类型 ID0x4cce0会被解释为https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json。由于_setURI无法用URI事件有意义地表达该函数不发射事件。3. 余额查询balanceOf(account, id)要求account ! address(0)否则 revertERC1155: balance query for the zero address。balanceOfBatch(accounts, ids)要求两数组长度相等否则ERC1155: accounts and ids length mismatch并逐个校验零地址后循环读取返回余额数组。4. 授权管理setApprovalForAll(operator, approved)禁止给自己授权ERC1155: setting approval status for self随后写入_operatorApprovals并发射ApprovalForAll。isApprovedForAll(account, operator)纯查询。5. 安全单笔转账safeTransferFrom执行顺序与校验ERC1155.sol校验to ! address(0)校验调用者是from本人或已被from全量授权调用_beforeTokenTransfer钩子用SafeMath.sub扣减from余额ERC1155: insufficient balance for transfer、add增加to余额发射TransferSingle调用_doSafeTransferAcceptanceCheck做接收方检查。6. 安全批量转账safeBatchTransferFrom逻辑与单笔一致额外要求ids.length amounts.length否则ERC1155: ids and amounts length mismatch循环更新每对(id, amount)后发射TransferBatch最后执行批量接收检查。7. 内部铸造与销毁基础合约仅暴露 internal 版本外部铸造权限由子类控制_mint(account, id, amount, data)/_mintBatch(to, ids, amounts, data)校验零地址与长度匹配后累加余额发射TransferSingle/TransferBatchfrom为address(0)并做接收方检查。_burn(account, id, amount)/_burnBatch(account, ids, amounts)校验零地址与长度匹配后扣减余额ERC1155: burn amount exceeds balance发射事件to为address(0)。8. 可扩展钩子_beforeTokenTransfer所有转账、铸造、销毁含批量变体在更新状态前都会调用_beforeTokenTransfer。实现默认空实现子类可覆写它实现手续费、白名单、清算等逻辑单笔操作时传入的ids/amounts为长度 1 的数组由_asSingletonArray构造。四、安全接收检查与ERC1155TokenReceiver抽象基类_doSafeTransferAcceptanceCheck与_doSafeBatchTransferAcceptanceCheckERC1155.sol是“安全转账”的落地实现仅当to是合约to.isContract()时尝试调用对应的接收回调并比对返回值返回值不等于onERC1155Received.selector→ revertERC1155: ERC1155Receiver rejected tokens回调 revert 带原因 → 透传原因回调未实现catch兜底→ revertERC1155: transfer to non ERC1155Receiver implementer。配套的 ERC1155TokenReceiver.sol 提供一个抽象基类构造时用onERC1155Received.selector ^ onERC1155BatchReceived.selector作为接口 ID 注册到 ERC165子类只需实现两个回调即可被识别为合法的 ERC1155 接收方。EIP-3267 中的 BidOnAddresses.sol 正是这样做的它在构造时注册BidOnAddresses(0).onERC1155Received.selector ^ BidOnAddresses(0).onERC1155BatchReceived.selector使竞拍合约本身成为可接收 ERC1155 代币的合约。五、ERC1155WithTotals为 EIP-3267 增加总供应量视图ERC1155WithTotals.sol 是本目录 README 未单独列出的重要扩展README 的 sections 只列出三个合约但它与ERC1155同目录且被 EIP-3267 业务合约直接继承。它在ERC1155之上增加了mapping(uint256 uint256) private totalBalances; function totalSupply(uint256 id) public view returns (uint256);构造时透传uri_给ERC1155(uri_)覆写_mint、_burn并新增_batchMint、_batchBurn统一经由私有_doMint/_doBurn同时更新_balances与totalBalances保证代币类型级总供应量与账户余额始终一致提供了totalSupply(id)视图对应“总供应量查询”类接口源码注释标注 conforms toIERC1155Views。EIP-3267 中的实际用法从源码结构看该扩展被 BaseLock.sol 继承import { ERC1155WithTotals } ...构造时调用ERC1155WithTotals(_uri)并配合 OpenZeppelin 的IERC1155BaseLock.sol作为collateralContractAddress参数类型使用。BaseLock 中通过totalSupply(_donatedPerOracleCollateralTokenId)、totalSupply(_condition)等读取总供应量见 BaseLock.sol 与 #L478-L483用于计算 oracle 捐赠代币总量与条件代币供应BaseRestorableSalary.sol同样引用了该模块说明 ERC1155 在 EIP-3267 中承担“条件代币 / 担保物 / 捐赠记录”的多代币载体角色。六、编译与依赖约束根据 assets/eip-3267/contracts/README.md 的说明使用该 ERC1155 模块时需注意环境约束合约按Solidity 0.7.6编译ERC1155.sol自身声明0.6.0 0.8.0接口与扩展声明^0.7.1Node.js 依赖openzeppelin/contracts 3.3.0提供IERC165、ERC165、SafeMath、Address、Context、IERC1155MetadataURI、IERC1155Receiver等、abdk-libraries-solidity 2.4.0审计状态README 注明审计费用已支付、正在进行中源码中留有面向审计人员的 FIXME/TODO 注释EIP-3267 处于 draft 阶段计划部署的合约是SalaryWithDAO与DefaultDAOInterface。七、小结从标准模块到业务复用本目录提供了一个“教科书级”的 ERC1155 分层设计值得在阅读 EIP-3267 时重点对照接口与实现分离IERC1155定义标准表面合规必需ERC1155提供 OpenZeppelin 系的基础实现安全接收协议IERC1155TokenReceiver 魔术值检查保证代币不会“卡”在非接收合约中可组合扩展ERC1155WithTotals一行继承即可获得总供应量视图EIP-3267 的锁仓与薪资治理直接复用仓库定位该模块是 assets/eip-3267/contracts/README.md 所列 EIP-3267 draft 合约集的一部分配合 EIPS/eip-3267.md 可完整理解科学薪资提案的代币化机制。如需进一步验证实现细节可直接阅读 ERC1155.sol核心逻辑、ERC1155WithTotals.sol总供应扩展以及 BaseLock.sol业务侧调用示例。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考