import{loadFixture}from"@nomicfoundation/hardhat-network-helpers";import{expect}from"chai";import{ethers}from"hardhat";describe("FirstENSBankAndTrust",function(){describe("Receive and Claim Token",function(){it("Should ACCEPT/REJECT claimTo based on if ENS owner is msg.sender",asyncfunction(){...// Steps of testing:// 测试步骤:// mint to charlie// 铸造给 charlie// charlie send to ENSTrust and recorded under bob.xinbenlvethsf.eth// charlie 发送到 ENSTrust 并记录在 bob.xinbenlvethsf.eth 下// bob try to claimTo alice, first time it should be rejected// bob 尝试 claimTo alice,第一次应该被拒绝// bob then set the ENS record// bob 然后设置 ENS 记录// bob claim to alice, second time it should be accepted// bob claim to alice,第二次应该被接受// mint to charlie// 铸造给 charlieawaiterc721ForTesting.mint(charlie.address,fakeTokenId);// charlie send to ENSTrust and recorded under bob.xinbenlvethsf.eth// charlie 发送到 ENSTrust 并记录在 bob.xinbenlvethsf.eth 下awaiterc721ForTesting.connect(charlie)["safeTransferFrom(address,address,uint256,bytes)"](charlie.address,firstENSBankAndTrust.address,fakeTokenId,fakeReceiverENSNamehash);// bob try to claimTo alice, first time it should be rejected// bob 尝试 claimTo alice,第一次应该被拒绝awaitexpect(firstENSBankAndTrust.connect(bob).claimTo(alice.address,fakeReceiverENSNamehash,firstENSBankAndTrust.address,fakeTokenId)).to.be.rejectedWith("ENSTokenHolder: node not owned by sender");// bob then set the ENS record// bob 然后设置 ENS 记录awaitensForTesting.setOwner(fakeReceiverENSNamehash,bob.address);// bob claim to alice, second time it should be accepted// bob claim to alice,第二次应该被接受awaitexpect(firstENSBankAndTrust.connect(bob).claimTo(alice.address,fakeReceiverENSNamehash,erc721ForTesting.address,fakeTokenId));});});});
参考实现
pragmasolidity^0.8.9;contractFirstENSBankAndTrustisIERC721Receiver,Ownable{functiongetENS()publicviewreturns(ENS){returnENS(ensAddress);}functionsetENS(addressnewENSAddress)publiconlyOwner{ensAddress=newENSAddress;}// @dev This function is called by the owner of the token to approve the transfer of the token
// @dev 此函数由 token 的所有者调用,以批准 token 的转移
// @param data MUST BE the ENS node of the intended token receiver this ENSHoldingServiceForNFT is holding on behalf of.
// @param data 必须是此 ENSHoldingServiceForNFT 代表的预期 token 接收者的 ENS 节点。
functiononERC721Received(addressoperator,address/*from*/,uint256tokenId,bytescalldatadata)externaloverridereturns(bytes4){require(data.length==32,"ENSTokenHolder: last data field must be ENS node.");// --- START WARNING ---
// --- 开始警告 ---
// DO NOT USE THIS IN PROD
// 不要在生产环境中使用
// this is just a demo purpose of using extraData for node information
// 这只是使用 extraData 获取节点信息的演示目的
// In prod, you should use a struct to store the data. struct should clearly identify the data is for ENS
// 在生产环境中,您应该使用一个结构体来存储数据。结构体应该清楚地标识数据用于 ENS
// rather than anything else.
// 而不是其他任何东西。
bytes32ensNode=bytes32(data[0:32]);// --- END OF WARNING ---
// --- 结束警告 ---
addToHolding(ensNode,operator,tokenId);// conduct the book keeping
// 进行簿记
returnERC721_RECEIVER_MAGICWORD;}functionclaimTo(addressto,bytes32ensNode,addresstokenContractuint256tokenId)public{require(getENS().owner(ensNode)==msg.sender,"ENSTokenHolder: node not owned by sender");removeFromHolding(ensNode,tokenContract,tokenId);IERC721(tokenContract).safeTransferFrom(address(this),to,tokenId);}}