claimTo MUST check if msg.sender is the owner of the ENS node identified by bytes32 ensNode (and/or approved by the domain in implementation-specific ways). The compliant contract then MUST make a call to the safeTransferFrom function of EIP-721 or EIP-1155.
Any ensNode is allowed.
Rationale
ENS was chosen because it is a well-established scoped ownership namespace.
This is nonetheless compatible with other scoped ownership namespaces.
We didn’t expose getters or setters for ensRoot because it is outside of the scope of this EIP.
Backwards Compatibility
No backward compatibility issues were found.
Test Cases
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 send to ENSTrust and recorded under bob.xinbenlvethsf.eth// bob try to claimTo alice, first time it should be rejected// bob then set the ENS record// bob claim to alice, second time it should be accepted// mint to charlieawaiterc721ForTesting.mint(charlie.address,fakeTokenId);// charlie send to ENSTrust and recorded under bob.xinbenlvethsf.ethawaiterc721ForTesting.connect(charlie)["safeTransferFrom(address,address,uint256,bytes)"](charlie.address,firstENSBankAndTrust.address,fakeTokenId,fakeReceiverENSNamehash);// bob try to claimTo alice, first time it should be rejectedawaitexpect(firstENSBankAndTrust.connect(bob).claimTo(alice.address,fakeReceiverENSNamehash,firstENSBankAndTrust.address,fakeTokenId)).to.be.rejectedWith("ENSTokenHolder: node not owned by sender");// bob then set the ENS recordawaitensForTesting.setOwner(fakeReceiverENSNamehash,bob.address);// bob claim to alice, second time it should be acceptedawaitexpect(firstENSBankAndTrust.connect(bob).claimTo(alice.address,fakeReceiverENSNamehash,erc721ForTesting.address,fakeTokenId));});});});
Reference Implementation
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
// @param data MUST BE the ENS node of the intended token receiver this ENSHoldingServiceForNFT is holding on behalf of.
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
// In prod, you should use a struct to store the data. struct should clearly identify the data is for 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);}}
Zainan Victor Zhou (@xinbenlv), "ERC-5298: ENS Trust to hold NFTs under ENS name [DRAFT]," Ethereum Improvement Proposals, no. 5298, July 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5298.