import{loadFixture}from"@nomicfoundation/hardhat-toolbox/network-helpers";import{expect}from"chai";import{ethers}from"hardhat";constNAME="NAME";constSYMBOL="SYMBOL";constTOKEN_ID=1234;constEXPIRATION=2000000000;constYEAR=31536000;describe("ERC7507",function(){asyncfunctiondeployContractFixture(){const[deployer,owner,user1,user2]=awaitethers.getSigners();constcontract=awaitethers.deployContract("ERC7507",[NAME,SYMBOL],deployer);awaitcontract.mint(owner,TOKEN_ID);return{contract,owner,user1,user2};}describe("Functions",function(){it("Should not set user if not owner or approved",asyncfunction(){const{contract,user1}=awaitloadFixture(deployContractFixture);awaitexpect(contract.setUser(TOKEN_ID,user1,EXPIRATION)).to.be.revertedWith("ERC7507: caller is not owner or approved");});it("Should return zero expiration for nonexistent user",asyncfunction(){const{contract,user1}=awaitloadFixture(deployContractFixture);expect(awaitcontract.userExpires(TOKEN_ID,user1)).to.equal(0);});it("Should set users and then update",asyncfunction(){const{contract,owner,user1,user2}=awaitloadFixture(deployContractFixture);awaitcontract.connect(owner).setUser(TOKEN_ID,user1,EXPIRATION);awaitcontract.connect(owner).setUser(TOKEN_ID,user2,EXPIRATION);expect(awaitcontract.userExpires(TOKEN_ID,user1)).to.equal(EXPIRATION);expect(awaitcontract.userExpires(TOKEN_ID,user2)).to.equal(EXPIRATION);awaitcontract.connect(owner).setUser(TOKEN_ID,user1,EXPIRATION+YEAR);awaitcontract.connect(owner).setUser(TOKEN_ID,user2,0);expect(awaitcontract.userExpires(TOKEN_ID,user1)).to.equal(EXPIRATION+YEAR);expect(awaitcontract.userExpires(TOKEN_ID,user2)).to.equal(0);});});describe("Events",function(){it("Should emit event when set user",asyncfunction(){const{contract,owner,user1}=awaitloadFixture(deployContractFixture);awaitexpect(contract.connect(owner).setUser(TOKEN_ID,user1,EXPIRATION)).to.emit(contract,"UpdateUser").withArgs(TOKEN_ID,user1.address,EXPIRATION);});});});
// SPDX-License-Identifier: CC0-1.0
pragmasolidity^0.8.0;import"@openzeppelin/contracts/token/ERC721/ERC721.sol";import"./IERC7507.sol";contractERC7507isERC721,IERC7507{mapping(uint256=>mapping(address=>uint64))private_expires;constructor(stringmemoryname,stringmemorysymbol)ERC721(name,symbol){}functionsupportsInterface(bytes4interfaceId)publicviewvirtualoverridereturns(bool){returninterfaceId==type(IERC7507).interfaceId||super.supportsInterface(interfaceId);}functionuserExpires(uint256tokenId,addressuser)publicviewvirtualoverridereturns(uint256){require(_exists(tokenId),"ERC7507: query for nonexistent token");return_expires[tokenId][user];}functionsetUser(uint256tokenId,addressuser,uint64expires)publicvirtualoverride{require(_isApprovedOrOwner(_msgSender(),tokenId),"ERC7507: caller is not owner or approved");_expires[tokenId][user]=expires;emitUpdateUser(tokenId,user,expires);}}
Ming Jiang (@minkyn), Zheng Han (@hanbsd), Fan Yang (@fayang), "ERC-7507: 多用户 NFT 扩展 [DRAFT]," Ethereum Improvement Proposals, no. 7507, August 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7507.