# 初探ERC3525 **Published by:** [Omen](https://paragraph.com/@omen/) **Published on:** 2023-02-15 **URL:** https://paragraph.com/@omen/erc3525 ## Content ERC3525半同质化(semi-fungible)标准, ERC3525定义一个三重参数模型,用于表示Token的半同质化结构。 基于Id参数,保证了兼容ERC721同质化的特性,可以通过transfer在地址间转移,也可以实现aprrove方法; Value参数,类似ERC20标准的Token数量balance; Slot参数, 当两个不同ID的Token具有相同的Slot时,可视这两个Token是同质化的. 即通过SLOT可以判断不同ID间的Token是否为同质化的.TL;DRERC3525标准在非同质化ERC721通证的基础之上,通过引入Slot参数, 实现了TokenId级别的半同质化特性: 不同TokenId的Slot参数相同,则同质; 若不同,则非同质.引入同质化特性后, 即可加入Value参数, 标识单个TokenId内有多少数量(value)的Token( or 任何有含义的资产).ERC3525标准则在Slot和Value维度上, 扩展了类似ERC721的授权,转移和查询方法,具体见文.此外, ERC3525标准建议将metadata数据存于链上, 可以通过Slot来在链上索引Slot维度的metadata数据, 也可以实现TokenId维度的metadata获取.1 基本ERC3525标准继承自IERC165和IERC721标准interface IERC3525 /* is IERC165, IERC721 */ {...}.对比ERC721,以下从授权,转移和查询(approve, transfer and view)三个维度对ERC3525方法进行分类:1.1 关于授权(approve)// 721方法, msg.sender授权_tokenId的操作权限给_approved地址 function approve(address _approved, uint256 _tokenId) external payable; // 721方法, msg.sender授权(或取消授权)其所有权限给_operator地址 function setApprovalForAll(address _operator, bool _approved) external; // 721方法, 查询单个_tokenId的授权情况, 针对approve(address,uint256)方法 function getApproved(uint256 _tokenId) external view returns (address); // 721方法, 查询拥有者_owner地址的授权情况,针对setApprovalForAll方法 function isApprovedForAll(address _owner, address _operator) external view returns (bool); // 3525方法, msg.sender授权_tokenId的_value数量的操作权限给_operator地址 function approve(uint256 _tokenId, address _operator, uint256 _value) external payable; // 3525方法, 查询_operator操作地址对单个_tokenId的授权情况, 针对approve(uint256,address,uint256)方法 function allowance(uint256 _tokenId, address _operator) external view returns (uint256); 三个授权层级:(ERC721)针对单个地址的所有操作权限: setApprovalForAll(ERC721)针对单个TokenId的所有操作权限: approve(address, uint256)(ERC3525)针对单个TokenId内指定Value数量的操作权限: approve(uint256, address, uint256)根据以上三类授权层级, 分别有相应的查询方法. 在本文2.2部分可见, 扩展的IERC3525SlotApprovable标准还增加了Slot级别的授权层级;1.2 关于转移(transfer)// 721方法, 将_tokenId从_from地址转移至_to地址;附加校验_to地址是否为合约地址; 附加额外数据data; function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; // 721方法, 将_tokenId从_from地址转移至_to地址;附加额外校验, 一般为onERC721Received; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; // 721方法, 将_tokenId从_from地址转移至_to地址; function transferFrom(address _from, address _to, uint256 _tokenId) external payable; // 3525方法, 将单个_fromTokenId中_value数量转移至单个_toTokenId中; 要求_fromTokenId和_toTokenId是同质的, 即slot参数要相同; function transferFrom(uint256 _fromTokenId, uint256 _toTokenId, uint256 _value) external payable; // 3525方法, 将单个_fromTokenId中_value数量转移给_to地址; 若_to存在slot与_fromTokenId的tokenId, 则累加, 否则需要新创建一个tokenId; function transferFrom(uint256 _fromTokenId, address _to, uint256 _value) external payable returns (uint256); 两个转移层级:(ERC721)针对单个TokenId的转移(ERC3525)针对单个TokenId下Value的转移同质化转移: 相同Slot的token之间的Value值转移非同质化转移: 从Token到地址的Value值转移1.3 关于查询(view)如图, 相比ERC721包含的查询方法1和2,ERC3525增加了针对TokenId下的Value以及Slot的查询方法.ERC3525查询// 721方法, 查询_owner拥有TokenId的数量, 对应箭头1 function balanceOf(address _owner) external view returns (uint256); // 721方法, 查询_tokenId的拥有者, 对应箭头2 function ownerOf(uint256 _tokenId) external view returns (address); // 3525方法, 查询单个_tokenId目前拥有的Value数量, 对应箭头3 function balanceOf(uint256 _tokenId) external view returns (uint256); // 3525方法, 查询单个_tokenId对应的slot参数, 用于区分不同TokenId之间是否为同质的, 对应箭头4 function slotOf(uint256 _tokenId) external view returns (uint256); // 3525方法, 查询Value值的精度数(小数位数), 对应箭头5 function valueDecimals() external view returns (uint8); 2 扩展标准2.1 扩展slot枚举标准(IERC3525SlotEnumerable)继承自IERC3525和IERC721Enumerable: interface IERC3525SlotEnumerable is IERC3525 /* , IERC721Enumerable */ {...}. 在枚举TokenId的基础之上,实现了针对Slot的枚举方法. 该标准的ERC165标识符为:0x3b741b9e// 721Enumerable方法, 获取TokenId的总供应量 function totalSupply() external view returns (uint256); // 721Enumerable方法, 枚举获取TokenId function tokenByIndex(uint256 _index) external view returns (uint256); // 721Enumerable方法, 枚举获取Owner地址拥有的TokenId function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); // 3525SlotEnumerable方法, 获取Slot的总数, 类比totalSupply() function slotCount() external view returns (uint256); // 3525SlotEnumerable方法, 枚举获取Slot, 类比tokenByIndex(uint256) function slotByIndex(uint256 _index) external view returns (uint256); // 3525SlotEnumerable方法, 获取指定Slot的总数, (~~类比totalSupplyInOwner(address _owner) returns(uint256 amount), hhhhh~~) function tokenSupplyInSlot(uint256 _slot) external view returns (uint256); // 3525SlotEnumerable方法, 枚举指定Slot, 获取TokenId, 类比tokenOfOwnerByIndex(address, uint256) function tokenInSlotByIndex(uint256 _slot, uint256 _index) external view returns (uint256); 2.2 扩展slot授权标准(IERC3525SlotApprovable)继承自IERC3525,实现对slot维度的授权 该标准的ERC165标识符为:0xb688be58// 3525SlotApprovable方法, _owner授权(或取消授权)_slot的的操作权限给_operator地址 function setApprovalForSlot(address _owner, uint256 _slot, address _operator, bool _approved) external payable; // 3525SlotApprovable, 查询_operator对_owner拥有的_slot是否拥有操作权限 function isApprovedForSlot(address _owner, uint256 _slot, address _operator) external view returns (bool); 2.3 扩展元数据标准(IERC3525Metadata)继承自IERC3525和IERC721Metadata: interface IERC3525Metadata is IERC3525 /* , IERC721Metadata */ {...}. 该标准的ERC165标识符为:0xe1600902// 721Metadata方法, 该系列Token的名字 function name() external view returns (string _name); // 721Metadata方法, 该系列Token的符号 function symbol() external view returns (string _symbol); // 721Metadata方法, 指定TokenId的元数据: 可以是外部url, 也可以是直接由链上数据生成; // 标准建议返回以’data:application/json;‘起始的json格式数据; function tokenURI(uint256 _tokenId) external view returns (string); // 3525Metadata方法, 该系列Token整体的信息: 标准建议返回以’data:application/json;‘起始的json格式数据; function contractURI() external view returns (string memory); // 3525Metadata方法, 指定slot的元数据: 标准建议返回以’data:application/json;‘起始的json格式数据; function slotURI(uint256 _slot) external view returns (string memory); 关于contract, token和slot维度的metadata数据, 标准建议返回以`data:application/json;‘起始的json格式数据, 示例如下:function slotURI(uint256 slot_) public view virtual override returns (string memory) { return string( abi.encodePacked( // solhint-disable "data:application/json;base64,", Base64.encode( abi.encodePacked( '{"name":"', _slotDetails[slot_].name, '","description":"', _slotDetails[slot_].description, '","image":"', _slotDetails[slot_].image, '","properties":', _slotProperties(slot_), "}" ) ) // solhint-enable ) ); } 3 合约接收标准(Token Receiver)该标准的ERC165标识符为:0x009ce20binterface IERC3525Receiver { // @return bytes4(keccak256('onERC3525Received(address,uint256,uint256,uint256,bytes)')) == 0x009ce20b function onERC3525Received(address _operator, uint256 _fromTokenId, uint256 _toTokenId, uint256 _value, bytes calldata _data) external returns (bytes4); } ## Publication Information - [Omen](https://paragraph.com/@omen/): Publication homepage - [All Posts](https://paragraph.com/@omen/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@omen): Subscribe to updates