
图片资料:官方来源
在ERC-721合约里,setApprovalForAll(钱包界面常叫“Approve All”或“全部授权”)把某个operator地址加入owner在该合约下的授权集合。此后,operator可以转移该owner在这个合约里的全部NFT。它不改变当前所有权,只是给了operator转移权限。approve则只针对单个tokenId,授予指定地址转移这一枚NFT的权限。两者作用范围完全不同:前者按“合约+owner”生效,后者按“合约+tokenId”生效。
用一组假设持有说明范围
设钱包A持有系列甲(合约地址0x甲)的3枚:#11、#12、#13;同时持有系列乙(合约地址0x乙)的2枚:#1、#2。
对系列甲调用setApprovalForAll(operatorB, true)后,B可转移的是#11、#12、#13,共3枚,全部在0x甲内。系列乙的#1、#2不受影响,B若没有乙的授权就无法动它们。如果A之后又在0x甲里获得#14,B的operator权限同样覆盖它,因为判断依据是owner与合约,不是授权当时的持有清单。
若A改为只对#11调用approve(B, 11),B只能转移#11。同一合约下的#12、#13不在授权范围内,系列乙更不涉及。这里授予的只是转移权限,A仍是#11的owner,仍可以自己转移它。
授权不等于过户,单枚转移会清掉单枚批准
两种授权都不改变ownerOf的返回值。授权后,NFT仍属于A,A可以继续持有、转移或再次授权。ERC-721规定,单枚NFT发生转移时,该tokenId上原有的单枚批准会被重置为空;而operator授权是owner级别的状态,不随某一枚NFT转走而自动清除,需要owner另行撤销。
这解释了一个常见现象:某平台曾获得某枚NFT的单枚批准,NFT转手后,新owner并不会继承这笔单枚批准;但如果owner此前对该平台做过setApprovalForAll,平台对该owner在合约内的其余NFT仍有权限。
核对时要同时看三项
排查“为什么这个平台能转我的NFT”时,至少核对:合约地址、operator地址、授权范围。范围要区分是某tokenId的单枚批准,还是该合约下owner的全量operator授权。只看钱包里某个“已授权”标记不够,因为不同合约、不同operator是彼此独立的记录。
撤销时同样要对应到正确的层级:单枚授权撤销是把该tokenId的approved地址设为零地址;operator授权撤销是调用setApprovalForAll(operator, false)。撤销授权与取消市场上挂单是两件事:取消订单改变的是交易订单状态,授权状态不会因此自动归零,市场订单的具体逻辑不在本文展开。
容易混淆的两点
第一,Approve All不是“所有链、所有系列”的通行证。它只在调用它的那个ERC-721合约内、针对调用者owner生效。跨链或换一个合约地址,需要重新判断。
第二,operator可以转移NFT,这是标准赋予的能力。因此对不熟悉的operator做全量授权,等于把该合约下当前和未来持有的NFT转移入口一并交出。需要长期交互时,先确认合约地址与operator地址,再决定用单枚approve还是全量授权;用完后按对应层级撤销。