
图片资料:官方来源
在ERC-721里,一个tokenId通常只对应一个所有者,ownerOf能给出唯一答案。到了ERC-1155,同一个ID却可能同时出现在多个地址的余额里。这不是标准出错,而是两类标准对“一份资产”的定义不同。
按ERC-1155的设定,一个合约可以管理任意多种代币类型,每个id代表一种可配置的代币类型,拥有自己的元数据、供应量和其他属性;同质化、非同质化以及介于两者之间的配置都能放在同一个合约里。它用“余额”而不是“唯一所有权”来描述持有关系:balanceOf(address _owner, uint256 _id)返回某地址在某个ID上的数量,balanceOfBatch一次查询多组地址与ID的余额。所以在ERC-1155里,问“ID 7归谁”本身就不完整,更准确的问法是“某地址在ID 7上有多少份”。
假设某ERC-1155合约的ID 7上,地址甲持有3份、地址乙持有2份。这只说明这两个地址在该合约该ID上的余额分别为3和2,推不出ID 7的总发行量只有5。其他地址可能还持有ID 7,已销毁的数量也不会出现在这两个余额里。要得到当前总供应,需要把铸造量与销毁量相减;如果只统计累计铸造而忽略销毁,得到的数字会偏大。ERC-1155并不强制合约提供供应量查询接口,所以有些合约只能靠转账事件里的铸造(_from为零地址)和销毁(_to为零地址)记录去还原。把“甲3乙2”直接读成“总共5份”,是常见的误判。
ID的识别范围也容易混淆。ERC-1155的ID只在“链+合约地址+ID”这个组合内有意义。A合约的ID 7和B合约的ID 7是两个不同的代币类型,余额、元数据和规则都可能不同。区块浏览器里看到某个合约的ID 7有多个持有人,不能据此推断另一个合约的ID 7也如此。核对时先确认链和合约地址是否为目标对象,再看ID和地址;顺序反了,很容易把不同合约的同号ID放在一起比较。
从接口层面看,ERC-1155的safeTransferFrom带有_value参数,表示转移的数量;批量版本safeBatchTransferFrom用_ids和_values两个数组一一对应。同一ID因此可以在地址间拆分流转:转出方余额减少,接收方余额增加,事件记录的是数量变化,而不是所有权指针的转移。查询时用balanceOf,不要套用ERC-721的ownerOf思路,后者在ERC-1155接口里并不存在。
还有一个边界值得记住:余额为0和“从未接触过这个ID”在查询结果上都显示为0。某地址从未持有过ID 7,和持有后全部转出或销毁,balanceOf都返回0。要区分这两种情况,需要结合转账事件历史判断,不能只看当前余额。
实际核对某个地址在某个ID上的持有量,可以按这个顺序操作:先确认所选链与合约地址无误,再调用balanceOf传入目标地址和ID,必要时用balanceOfBatch一次查多个地址;若还想知道该ID的当前总供应,则另行统计铸造与销毁事件,并注明统计截止的区块高度。余额是查询时刻的快照,换一个区块高度,数字可能就变了。