如何向特定NFT持有者空投代币/NFT并实现领取权限控制
特定NFT持有者代币发放实现方案
你在BAYC主合约里找不到对应ERC20分发逻辑是正常的:BAYC发放的ApeCoin采用独立合约部署,分发逻辑没有写入BAYC的ERC721主合约,项目方先在固定区块高度对所有BAYC/MAYC持有者持仓做快照,用Merkle白名单的方式做资格校验,不需要实时跨合约读持仓状态。
两类通用实现路径
根据使用场景选对应方案即可:
- 快照+Merkle白名单方案
适合一次性、固定总量的空投场景(比如BAYC发ApeCoin)。实现逻辑:先选定快照区块高度,拉取该高度下所有目标NFT持有者的地址、对应可领取额度,整理成列表生成Merkle树,把Merkle根存在空投合约中。用户申领时,从项目方的链下服务获取对应地址的Merkle证明,调用合约申领方法时提交证明,合约验证证明有效、对应地址/NFT未领取过,就发放对应代币。
这个方案gas成本极低,不需要在链上做复杂的跨合约持仓校验,还能避免快照后NFT转卖导致的重复申领问题,是行业内空投的主流方案。核心要做hasClaimed映射标记领取状态,避免重复发放。 - 实时跨合约校验方案
适合你提到的「持有合约1NFT可领合约2NFT」的联动场景,不需要提前做快照,用户申领时合约实时校验持仓状态即可。
双ERC721联动免费申领实现要点
你要的两个ERC721合约联动的逻辑非常简单,核心是做好资格校验和防重复领取,最小实现逻辑如下:
- 部署合约2时,在构造函数中传入合约1的地址,存为不可变变量,减少后续调用gas。
- 不要按地址标记领取状态,要按合约1的NFT ID标记领取状态,避免一个NFT被转卖后新老持有者重复领取,也能支持持有多个合约1NFT的用户领多个合约2NFT。
- 核心申领逻辑参考最小可用代码:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/interfaces/IERC721.sol"; contract LinkedNFT is ERC721 { IERC721 public immutable originalNft; // 标记原NFT的tokenId是否已申领过新NFT mapping(uint256 => bool) public hasClaimed; uint256 public currentTokenId; constructor(address _originalNft) ERC721("LinkedNFT", "LNFT") { originalNft = IERC721(_originalNft); } /** * @param originalTokenId 用户持有的原NFT的tokenId */ function claim(uint256 originalTokenId) external { // 校验调用者是原NFT对应ID的当前持有人 require(originalNft.ownerOf(originalTokenId) == msg.sender, "Not the owner of target NFT"); // 校验该原NFT未申领过 require(!hasClaimed[originalTokenId], "This NFT already claimed"); hasClaimed[originalTokenId] = true; _safeMint(msg.sender, currentTokenId); currentTokenId++; } }
- 可选调整项:
- 如果要求单地址不管持有多少原NFT都只能领1个,把
hasClaimed的key改成用户地址即可,逻辑更简单。 - 如果需要限制申领窗口,可以增加截止时间变量,超过时间后claim方法不可调用。
- 如果要避免用户临时转NFT刷资格,可以增加持仓时长校验,要求用户持有原NFT超过一定区块数才能申领,普通场景不需要加这个逻辑。
- 如果要求单地址不管持有多少原NFT都只能领1个,把
注意避坑
不要在申领方法里尝试遍历查询用户的所有原NFT持仓,ERC721没有标准的批量查询持仓接口,遍历操作gas成本极高,还容易被恶意攻击。要么提前做快照用Merkle方案,要么让用户主动传入自己持有的原NFT ID,合约只做单个ID的所有权校验即可。
如果是发放固定总量的ERC20空投,优先选快照+Merkle方案,实时校验方案会导致用户可以在申领期临时买NFT刷空投,科学家刷量的成本极低,也没法保证发放的公平性。
内容的提问来源于stack exchange,提问作者Dakata
相关产品推荐
相关产品推荐

