From e4eb2f8d0d928ec8a7e2a88252b4829d1ccf577e Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Tue, 17 Oct 2023 21:18:46 +0900 Subject: [PATCH 01/24] feat: added the isNonTransferable variable and some functions --- hardhat/contracts/MintNFT.sol | 17 ++++++++ hardhat/test/MintNFT.ts | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index d506c01a..63d341b3 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -59,10 +59,13 @@ contract MintNFT is // Create a mapping to store NFT holders by event ID mapping(uint256 => uint256[]) private tokenIdsByEvent; address private operationControllerAddr; + // is non transferable via EventId + mapping(uint256 => bool) private isNonTransferable; event MintedNFTAttributeURL(address indexed holder, string url); event MintLocked(uint256 indexed eventId, bool isLocked); event ResetSecretPhrase(address indexed executor, uint256 indexed eventId); + event NonTransferable(uint256 indexed eventId, bool isNonTransferable); modifier onlyGroupOwner(uint256 _eventId) { IEventManager eventManager = IEventManager(eventManagerAddr); @@ -199,6 +202,14 @@ contract MintNFT is emit MintLocked(_eventId, _locked); } + function changeNonTransferable( + uint256 _eventId, + bool _isNonTransferable + ) external onlyGroupOwner(_eventId) whenNotPaused { + isNonTransferable[_eventId] = _isNonTransferable; + emit NonTransferable(_eventId, _isNonTransferable); + } + function resetSecretPhrase( uint256 _eventId, bytes32 _secretPhrase @@ -211,6 +222,12 @@ contract MintNFT is return isMintLocked[_eventId]; } + function getIsNonTransferable( + uint256 _eventId + ) external view returns (bool) { + return isNonTransferable[_eventId]; + } + function isHoldingEventNFTByAddress( address _addr, uint256 _eventId diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index dc9fb9d3..b74619d9 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -611,6 +611,81 @@ describe("mint locked flag", () => { }); }); +describe("non transferable flag", () => { + let mintNFT: MintNFT; + let eventManager: EventManager; + let operationController: OperationController; + + let createdGroupId: number; + const createdEventIds: number[] = []; + + let organizer: SignerWithAddress; + let participant1: SignerWithAddress; + let participant2: SignerWithAddress; + let relayer: SignerWithAddress; + + let correctProofCalldata!: any; + + before(async () => { + [organizer, participant1, participant2, relayer] = + await ethers.getSigners(); + + // generate proof + const { publicInputCalldata, proofCalldata } = await generateProof(); + [, mintNFT, eventManager, operationController] = await deployAll(relayer); + correctProofCalldata = publicInputCalldata[0]; + + // Create a Group and an Event + await createGroup(eventManager, "First Group", organizer); + const groupsList = await eventManager.getGroups(); + createdGroupId = groupsList[0].groupId.toNumber(); + + const createEventTxn = await eventManager.createEventRecord( + createdGroupId, + "event1", + "event1 description", + "2022-07-3O", + 10, + false, + correctProofCalldata, + attributes + ); + await createEventTxn.wait(); + const eventsList = await eventManager.getEventRecords(0, 0); + createdEventIds.push(eventsList[0].eventRecordId.toNumber()); + + const mintNftTxn = await mintNFT + .connect(participant1) + .mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + await mintNftTxn.wait(); + }); + + it("should get non transferable flag", async () => { + const flag = await mintNFT.connect(organizer).getIsNonTransferable(1); + expect(flag).equal(false); + expect(await mintNFT.ownerOf(0)).equal(participant1.address); + await expect( + mintNFT + .connect(participant1) + .transferFrom(participant1.address, participant2.address, 0) + ).not.to.be.reverted; + expect(await mintNFT.ownerOf(0)).equal(participant2.address); + }); + + it("No one but the owner should be able to change non transferable flag", async () => { + await expect( + mintNFT.connect(participant1).changeNonTransferable(1, false) + ).to.be.revertedWith("you are not event group owner"); + }); + + it("should not change if paused", async () => { + await operationController.connect(organizer).pause(); + await expect(mintNFT.connect(organizer).changeNonTransferable(1, false)).to + .be.reverted; + await operationController.connect(organizer).unpause(); + }); +}); + describe("reset secret phrase", () => { let mintNFT: MintNFT; let eventManager: EventManager; From 5302768ab2beaeb768ca1d2eca52f2a64737b618 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 00:08:25 +0900 Subject: [PATCH 02/24] feat: restricted transferFrom() and added setEventIdOfTokenIds() --- hardhat/contracts/MintNFT.sol | 40 +++++++++++++++++++++++++++++++++++ hardhat/test/MintNFT.ts | 13 ++++++++++++ 2 files changed, 53 insertions(+) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 63d341b3..d38c303a 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -59,6 +59,8 @@ contract MintNFT is // Create a mapping to store NFT holders by event ID mapping(uint256 => uint256[]) private tokenIdsByEvent; address private operationControllerAddr; + // Create a mapping to store event ID by token ID + mapping(uint256 => uint256) private eventIdOfTokenId; // is non transferable via EventId mapping(uint256 => bool) private isNonTransferable; @@ -207,6 +209,10 @@ contract MintNFT is bool _isNonTransferable ) external onlyGroupOwner(_eventId) whenNotPaused { isNonTransferable[_eventId] = _isNonTransferable; + if (tokenIdsByEvent[_eventId].length != 0) { + _setEventIdOfTokenIds(_eventId, tokenIdsByEvent[_eventId]); + } + emit NonTransferable(_eventId, _isNonTransferable); } @@ -347,4 +353,38 @@ contract MintNFT is } return holders; } + + function transferFrom( + address from, + address to, + uint256 tokenId + ) public virtual override { + uint256 eventId = eventIdOfTokenId[tokenId]; + if (eventId == 0) { + super.transferFrom(from, to, tokenId); + } else { + require(!isNonTransferable[eventId], "transfer is locked"); + super.transferFrom(from, to, tokenId); + } + } + + function setEventIdOfTokenIds(uint256 eveintId) external onlyOwner { + require(tokenIdsByEvent[eveintId].length != 0, ""); + _setEventIdOfTokenIds(eveintId, tokenIdsByEvent[eveintId]); + } + + function _setEventIdOfTokenIds( + uint256 eveintId, + uint256[] memory tokenIds + ) internal { + uint256 lastTokenIdIndex = tokenIds.length - 1; + for (uint256 i = 0; i <= lastTokenIdIndex; i++) { + uint256 tokenId = tokenIds[lastTokenIdIndex - i]; + if (eventIdOfTokenId[tokenId] == eveintId) { + break; + } else { + eventIdOfTokenId[tokenId] = eveintId; + } + } + } } diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index b74619d9..ac8035cc 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -672,6 +672,19 @@ describe("non transferable flag", () => { expect(await mintNFT.ownerOf(0)).equal(participant2.address); }); + it("should change non transferable flag by owner", async () => { + await mintNFT.connect(organizer).changeNonTransferable(1, true); + const flag = await mintNFT.connect(organizer).getIsNonTransferable(1); + expect(flag).equal(true); + expect(await mintNFT.ownerOf(0)).equal(participant2.address); + await expect( + mintNFT + .connect(participant2) + .transferFrom(participant2.address, participant1.address, 0) + ).to.be.reverted; + expect(await mintNFT.ownerOf(0)).equal(participant2.address); + }); + it("No one but the owner should be able to change non transferable flag", async () => { await expect( mintNFT.connect(participant1).changeNonTransferable(1, false) From 8d39eaa51ad66e8646ae4359b363d00cb6b1ebd5 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 12:42:32 +0900 Subject: [PATCH 03/24] fix: changed transferFrom() to _transfer() --- hardhat/contracts/MintNFT.sol | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index d38c303a..702fcf3f 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -354,17 +354,17 @@ contract MintNFT is return holders; } - function transferFrom( + function _transfer( address from, address to, uint256 tokenId - ) public virtual override { + ) internal virtual override { uint256 eventId = eventIdOfTokenId[tokenId]; - if (eventId == 0) { - super.transferFrom(from, to, tokenId); - } else { + if (eventId != 0) { require(!isNonTransferable[eventId], "transfer is locked"); - super.transferFrom(from, to, tokenId); + super._transfer(from, to, tokenId); + } else { + super._transfer(from, to, tokenId); } } @@ -377,13 +377,14 @@ contract MintNFT is uint256 eveintId, uint256[] memory tokenIds ) internal { - uint256 lastTokenIdIndex = tokenIds.length - 1; - for (uint256 i = 0; i <= lastTokenIdIndex; i++) { - uint256 tokenId = tokenIds[lastTokenIdIndex - i]; - if (eventIdOfTokenId[tokenId] == eveintId) { - break; - } else { + uint256 lastIndex = tokenIds.length - 1; + for (uint256 i = 0; i <= lastIndex; i++) { + uint256 tokenId = tokenIds[lastIndex - i]; + + if (eventIdOfTokenId[tokenId] != eveintId) { eventIdOfTokenId[tokenId] = eveintId; + } else { + break; } } } From 515293b4d4e2a444abc909fc3929722452cafc81 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 13:00:22 +0900 Subject: [PATCH 04/24] fix: arguments of setEventIdOfTokenIds() --- hardhat/contracts/MintNFT.sol | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 702fcf3f..3c31b787 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -368,15 +368,19 @@ contract MintNFT is } } - function setEventIdOfTokenIds(uint256 eveintId) external onlyOwner { - require(tokenIdsByEvent[eveintId].length != 0, ""); - _setEventIdOfTokenIds(eveintId, tokenIdsByEvent[eveintId]); + function setEventIdOfTokenIds( + uint256 eveintId, + uint256[] memory tokenIds + ) external onlyOwner { + _setEventIdOfTokenIds(eveintId, tokenIds); } function _setEventIdOfTokenIds( uint256 eveintId, uint256[] memory tokenIds ) internal { + require(tokenIds.length != 0, "tokenIds is blank"); + uint256 lastIndex = tokenIds.length - 1; for (uint256 i = 0; i <= lastIndex; i++) { uint256 tokenId = tokenIds[lastIndex - i]; From b8d29ce8b4728e0f8c1934a69e50ef6d6920e257 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 13:01:47 +0900 Subject: [PATCH 05/24] feat: added eventIdOfTokenId into mintParticipateNFT() --- hardhat/contracts/MintNFT.sol | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 3c31b787..d16add97 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -168,9 +168,12 @@ contract MintNFT is metaDataURL = specialMetaDataURL; } - nftMetaDataURL[_tokenIds.current()] = metaDataURL; - tokenIdsByEvent[_eventId].push(_tokenIds.current()); - _safeMint(_msgSender(), _tokenIds.current()); + uint256 tokenId = _tokenIds.current(); + + nftMetaDataURL[tokenId] = metaDataURL; + tokenIdsByEvent[_eventId].push(tokenId); + eventIdOfTokenId[tokenId] = _eventId; + _safeMint(_msgSender(), tokenId); _tokenIds.increment(); emit MintedNFTAttributeURL(_msgSender(), metaDataURL); From 6a9e3b6a455109e874b926f7f599cc0b2cb9703e Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 13:03:59 +0900 Subject: [PATCH 06/24] feat: changed _safeMint location --- hardhat/contracts/MintNFT.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index d16add97..0cc77c64 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -173,9 +173,11 @@ contract MintNFT is nftMetaDataURL[tokenId] = metaDataURL; tokenIdsByEvent[_eventId].push(tokenId); eventIdOfTokenId[tokenId] = _eventId; - _safeMint(_msgSender(), tokenId); _tokenIds.increment(); + + _safeMint(_msgSender(), tokenId); + emit MintedNFTAttributeURL(_msgSender(), metaDataURL); } From 8c49bd790956dd9f0ef2331e9bc51bb696a7f424 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:55:40 +0900 Subject: [PATCH 07/24] feat: added getEventIdOfTokenId() and tests --- hardhat/contracts/MintNFT.sol | 6 ++++++ hardhat/test/MintNFT.ts | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 0cc77c64..5c4dc3a2 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -359,6 +359,12 @@ contract MintNFT is return holders; } + function getEventIdOfTokenId( + uint256 _tokenId + ) public view returns (uint256) { + return eventIdOfTokenId[_tokenId]; + } + function _transfer( address from, address to, diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index ac8035cc..d47cb1ee 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -207,6 +207,8 @@ describe("MintNFT", function () { const nftAttribute = await mintNFT.tokenURI(0); expect(nftAttribute).equal("ipfs://hogehoge/count0.json"); + + expect(await mintNFT.getEventIdOfTokenId(0)).equal(createdEventIds[0]); }); it("fail to mint when event MintLocked", async () => { @@ -335,6 +337,8 @@ describe("MintNFT", function () { proofCalldata ); await mintNftTxn.wait(); + expect(await mintNFT.getEventIdOfTokenId(0)).equal(createdEventIds[0]); + const { proofCalldata: proofCalldata2 } = await generateProof(); const mintNftTxn2 = await mintNFT .connect(participant1) @@ -344,6 +348,8 @@ describe("MintNFT", function () { proofCalldata2 ); await mintNftTxn2.wait(); + expect(await mintNFT.getEventIdOfTokenId(1)).equal(createdEventIds[0]); + const { proofCalldata: proofCalldata3 } = await generateProof(); const mintNftTxn3 = await mintNFT .connect(participant2) @@ -353,6 +359,8 @@ describe("MintNFT", function () { proofCalldata3 ); await mintNftTxn3.wait(); + expect(await mintNFT.getEventIdOfTokenId(2)).equal(createdEventIds[0]); + const { proofCalldata: proofCalldata4 } = await generateProof(); const mintNftTxn4 = await mintNFT .connect(participant1) @@ -362,6 +370,8 @@ describe("MintNFT", function () { proofCalldata4 ); await mintNftTxn4.wait(); + expect(await mintNFT.getEventIdOfTokenId(3)).equal(createdEventIds[1]); + const { proofCalldata: proofCalldata5 } = await generateProof(); const mintNftTxn5 = await mintNFT .connect(participant1) @@ -371,6 +381,7 @@ describe("MintNFT", function () { proofCalldata5 ); await mintNftTxn5.wait(); + expect(await mintNFT.getEventIdOfTokenId(4)).equal(createdEventIds[2]); }); it("get owners of the tokens", async () => { const tokens = [0, 1, 2, 3, 4]; From f75ce790a40e326749861e1f26178fb401a4ce7e Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:56:54 +0900 Subject: [PATCH 08/24] feat: added setEventIdOfTokenIdsBatch() to MintNFT.sol --- hardhat/contracts/MintNFT.sol | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 5c4dc3a2..7c029c0d 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -386,6 +386,21 @@ contract MintNFT is _setEventIdOfTokenIds(eveintId, tokenIds); } + function setEventIdOfTokenIdsBatch( + uint256[] memory eventIds, + uint256[][] memory tokenIdsArr + ) external onlyOwner { + uint256 eventIdsLength = eventIds.length; + + require(eventIdsLength == tokenIdsArr.length, "length is not match"); + + for (uint256 i = 0; i < eventIdsLength; i++) { + if (tokenIdsArr[i].length != 0) { + _setEventIdOfTokenIds(eventIds[i], tokenIdsArr[i]); + } + } + } + function _setEventIdOfTokenIds( uint256 eveintId, uint256[] memory tokenIds From c0b76212d735b28eecde4e1fd20fa662dbb38d0a Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 21:43:47 +0900 Subject: [PATCH 09/24] refactor: functions related to eventIdOfTokenId --- hardhat/contracts/MintNFT.sol | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 7c029c0d..22f75352 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -214,9 +214,6 @@ contract MintNFT is bool _isNonTransferable ) external onlyGroupOwner(_eventId) whenNotPaused { isNonTransferable[_eventId] = _isNonTransferable; - if (tokenIdsByEvent[_eventId].length != 0) { - _setEventIdOfTokenIds(_eventId, tokenIdsByEvent[_eventId]); - } emit NonTransferable(_eventId, _isNonTransferable); } @@ -380,10 +377,10 @@ contract MintNFT is } function setEventIdOfTokenIds( - uint256 eveintId, + uint256 eventId, uint256[] memory tokenIds ) external onlyOwner { - _setEventIdOfTokenIds(eveintId, tokenIds); + _setEventIdOfTokenIds(eventId, tokenIds); } function setEventIdOfTokenIdsBatch( @@ -394,27 +391,27 @@ contract MintNFT is require(eventIdsLength == tokenIdsArr.length, "length is not match"); - for (uint256 i = 0; i < eventIdsLength; i++) { + for (uint256 i = 0; i < eventIdsLength; ) { if (tokenIdsArr[i].length != 0) { _setEventIdOfTokenIds(eventIds[i], tokenIdsArr[i]); } + + unchecked { + ++i; + } } } function _setEventIdOfTokenIds( - uint256 eveintId, + uint256 eventId, uint256[] memory tokenIds ) internal { - require(tokenIds.length != 0, "tokenIds is blank"); - - uint256 lastIndex = tokenIds.length - 1; - for (uint256 i = 0; i <= lastIndex; i++) { - uint256 tokenId = tokenIds[lastIndex - i]; + uint256 tokenIdsLength = tokenIds.length; + for (uint256 i = 0; i < tokenIdsLength; ) { + eventIdOfTokenId[tokenIds[i]] = eventId; - if (eventIdOfTokenId[tokenId] != eveintId) { - eventIdOfTokenId[tokenId] = eveintId; - } else { - break; + unchecked { + ++i; } } } From 52a2a0c328109b60f8b4760689e94147f84011f9 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 22:47:31 +0900 Subject: [PATCH 10/24] feat: added getTOkenIdsByEvent() to MintNFT.sol --- hardhat/contracts/MintNFT.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 22f75352..782e8923 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -356,6 +356,12 @@ contract MintNFT is return holders; } + function getTokenIdsByEvent( + uint256 eventId + ) external view returns (uint256[] memory) { + return tokenIdsByEvent[eventId]; + } + function getEventIdOfTokenId( uint256 _tokenId ) public view returns (uint256) { From 908e9c0b9d7293b8dd2e534df82ea8e0df66a34e Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sat, 28 Oct 2023 22:48:22 +0900 Subject: [PATCH 11/24] added: script of setEventIdOfTokenIdsBatch --- hardhat/scripts/updateEventIdOfTokenId.ts | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 hardhat/scripts/updateEventIdOfTokenId.ts diff --git a/hardhat/scripts/updateEventIdOfTokenId.ts b/hardhat/scripts/updateEventIdOfTokenId.ts new file mode 100644 index 00000000..038a03a3 --- /dev/null +++ b/hardhat/scripts/updateEventIdOfTokenId.ts @@ -0,0 +1,53 @@ +import { ethers } from "hardhat"; +import { MintNFT, EventManager } from "../typechain"; +import { BigNumber } from "ethers"; + +const MINT_NFT_ADDRESS = "0xC3894D90dF7EFCAe8CF34e300CF60FF29Db9a868"; +const EVENT_MANAGER_ADDRESS = "0x4fe4F50B719572b3a5A33516da59eC43F51F4A45"; + +async function main() { + const MintNFTFactory = await ethers.getContractFactory("MintNFT"); + const mintNFT = MintNFTFactory.attach(MINT_NFT_ADDRESS) as MintNFT; + + // EventManagerのインスタンスを作成 + const EventManagerFactory = await ethers.getContractFactory("EventManager"); + const eventManager = EventManagerFactory.attach( + EVENT_MANAGER_ADDRESS + ) as EventManager; + + let eventIds: number[] = []; + let tokenIdsArr: number[][] = []; + + const eventRecordCountBigNumber = await eventManager.getEventRecordCount(); + const eventRecordCount = eventRecordCountBigNumber.toNumber(); + console.log("eventRecordCount", eventRecordCount); + + for (let i = 1; i <= eventRecordCount; i++) { + eventIds.push(i); + + // @todo コントラクトをアップグレード後、以下のコメントアウトを外す + // const tokenIds: BigNumber[] = await mintNFT.getTokenIdsByEvent(i); + + // tokenIdsArr.push(tokenIds.map((tokenId) => tokenId.toNumber())); + } + console.log("eventIds", eventIds); + console.log("tokenIdToEventIds", tokenIdsArr); + + // @todo コントラクトをアップグレード後、以下のコメントアウトを外す + // await (await mintNFT.setEventIdOfTokenIdsBatch(eventIds, tokenIdsArr)).wait(); + + // const lastEventIdOfTokenIds = tokenIdsArr[eventIds.length - 1]; + + // console.log("lastEventIdOfTokenIds", lastEventIdOfTokenIds); + + // const eventIdOfTokenId = await mintNFT.getEventIdOfTokenId( + // lastEventIdOfTokenIds[lastEventIdOfTokenIds.length - 1] + // ); + + // console.log("check eventIdOfTokenId", eventIdOfTokenId.toNumber()); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); From 94e861022a39fa433f0fafc8be924d87ca4927cb Mon Sep 17 00:00:00 2001 From: nfttakerun Date: Tue, 7 Nov 2023 21:22:33 +0900 Subject: [PATCH 12/24] Burn by user --- hardhat/contracts/MintNFT.sol | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 02cd95a4..124f7563 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -286,8 +286,15 @@ contract MintNFT is return _nftAttributeRecords; } - function burn(uint256 tokenId) public onlyOwner { - _burn(tokenId); + // 既存の burn 関数の名前を変更 + function burnByOwner(uint256 tokenId) public onlyOwner { + _burn(tokenId); + } + + // ユーザーが自身のNFTをバーンできるようにする新しい burn 関数 + function burn(uint256 tokenId) public { + require(_isApprovedOrOwner(_msgSender(), tokenId), "caller is not owner nor approved"); + _burn(tokenId); } function tokenURI( From b84868341d9ea4071abd2f33c73a36dfb8676ad9 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Fri, 10 Nov 2023 10:57:12 +0900 Subject: [PATCH 13/24] refactor: Removed unnecessary if statements --- hardhat/contracts/MintNFT.sol | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 782e8923..8d34d8b5 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -373,13 +373,11 @@ contract MintNFT is address to, uint256 tokenId ) internal virtual override { - uint256 eventId = eventIdOfTokenId[tokenId]; - if (eventId != 0) { - require(!isNonTransferable[eventId], "transfer is locked"); - super._transfer(from, to, tokenId); - } else { - super._transfer(from, to, tokenId); - } + require( + !isNonTransferable[eventIdOfTokenId[tokenId]], + "transfer is locked" + ); + super._transfer(from, to, tokenId); } function setEventIdOfTokenIds( From 1ade1c5941da249cf72cb0de3e65ba70182dfdf9 Mon Sep 17 00:00:00 2001 From: nfttakerun Date: Sat, 18 Nov 2023 17:38:22 +0900 Subject: [PATCH 14/24] Burn by user --- hardhat/test/MintNFT.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index 9038b415..31a3f459 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -251,6 +251,10 @@ describe("MintNFT", function () { 0 ); + // participant2がorganizerにトークンの操作を承認 + await mintNFT.connect(participant2).approve(organizer.address, tokenId); + + // 承認後にburnを実行 await mintNFT.connect(organizer).burn(tokenId); expect(await mintNFT.balanceOf(participant2.address)).equal(0); }); From 3d37d04f1fddd2845771f3a8f7fe5c7df3b8d58c Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:51:51 +0900 Subject: [PATCH 15/24] update: create event form for Non transferable option --- .../components/organisms/CreateEventForm.tsx | 29 +++++++++++++++++++ frontend/src/hooks/useEvent.ts | 1 + frontend/src/locales/en.ts | 4 +++ frontend/src/locales/ja.ts | 4 +++ frontend/types/Event.ts | 1 + 5 files changed, 39 insertions(+) diff --git a/frontend/src/components/organisms/CreateEventForm.tsx b/frontend/src/components/organisms/CreateEventForm.tsx index f51e667b..92234c78 100644 --- a/frontend/src/components/organisms/CreateEventForm.tsx +++ b/frontend/src/components/organisms/CreateEventForm.tsx @@ -47,6 +47,7 @@ interface EventFormData { secretPhrase: string; mintLimit: number; useMtx: "true" | "false"; + useNtt: "true" | "false"; nfts: NFT.NFTImage[]; } @@ -80,6 +81,7 @@ const CreateEventForm: FC = ({ address }) => { secretPhrase: "", mintLimit: 10, useMtx: undefined, + useNtt: undefined, nfts: [ { name: "", requiredParticipateCount: 0, description: "", image: "" }, ], @@ -114,6 +116,7 @@ const CreateEventForm: FC = ({ address }) => { secretPhrase: formData.secretPhrase, mintLimit: Number(formData.mintLimit), useMtx: formData.useMtx === "true", + useNtt: formData.useNtt === "false", attributes: nftAttributes, }; await createEvent(params); @@ -437,6 +440,32 @@ const CreateEventForm: FC = ({ address }) => { )} + + {t.EVENT_USE_NTT} + + ( + <> + + + {t.EVENT_USE_NTT_FALSE} + + {t.EVENT_USE_NTT_TRUE} + + {errors.useNtt?.message} + + )} + /> + + {t.EVENT_SECRETPHRASE} diff --git a/frontend/src/hooks/useEvent.ts b/frontend/src/hooks/useEvent.ts index 2599e79c..df464b18 100644 --- a/frontend/src/hooks/useEvent.ts +++ b/frontend/src/hooks/useEvent.ts @@ -214,6 +214,7 @@ export const useCreateEvent = (address: string) => { `${startDateTime}/${endDateTime}`, params.mintLimit, params.useMtx, + params.useNtt, proof?.publicInputCalldata[0], params.attributes, ], diff --git a/frontend/src/locales/en.ts b/frontend/src/locales/en.ts index 3eafea3f..eb3bc1a6 100644 --- a/frontend/src/locales/en.ts +++ b/frontend/src/locales/en.ts @@ -52,6 +52,10 @@ export default { EVENT_USE_MTX: "Taking on gas fee for participants", EVENT_USE_MTX_TRUE: "Yes", EVENT_USE_MTX_FALSE: "No", + // NFTをトランスファー不可にする(NFTを受け取った人は、NFTを他の人に送ることができなくなります) + EVENT_USE_NTT: "Make NFT non-transferable? (NFT recipients cannot transfer NFTs to others.))", + EVENT_USE_NTT_TRUE: "Yes", + EVENT_USE_NTT_FALSE: "No", EVENT_ESTIMATED_GAS_MTX: "Estimated deposit amount required to take on", EVENT_SECRETPHRASE: "SecretPhrase to mint", EVENT_SECRETPHRASE_DESC: diff --git a/frontend/src/locales/ja.ts b/frontend/src/locales/ja.ts index d15d8d6e..bc3eb9ac 100644 --- a/frontend/src/locales/ja.ts +++ b/frontend/src/locales/ja.ts @@ -53,6 +53,10 @@ export default { "ガス代を肩代わりして、参加者が無料でNFTを受け取れるようにする。", EVENT_USE_MTX_TRUE: "肩代わりする", EVENT_USE_MTX_FALSE: "肩代わりしない", + EVENT_USE_NTT: + "NFTをトランスファー不可にする(NFTを受け取った人は、NFTを他の人に送ることができなくなります)", + EVENT_USE_NTT_TRUE: "トランスファーを不可にする", + EVENT_USE_NTT_FALSE: "トランスファーを不可にしない", EVENT_ESTIMATED_GAS_MTX: "肩代わりに必要な予想デポジット金額", EVENT_SECRETPHRASE: "NFT受け取りのひみつの「あいことば」", EVENT_SECRETPHRASE_DESC: diff --git a/frontend/types/Event.ts b/frontend/types/Event.ts index 26bff5c5..555e1ec5 100644 --- a/frontend/types/Event.ts +++ b/frontend/types/Event.ts @@ -26,6 +26,7 @@ export namespace Event { secretPhrase: string; mintLimit: number; useMtx: boolean; + useNtt: boolean; attributes: { metaDataURL: string; requiredParticipateCount: number }[]; } } From 2b87b0c3efbc1fc0889fb80e19105f1c0426971a Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Thu, 7 Dec 2023 11:42:26 +0900 Subject: [PATCH 16/24] add: EventTransferLock component to EventEditSection --- .../molecules/EventTransferLock.tsx | 99 +++++++++++++++++++ .../components/organisms/EventEditSection.tsx | 5 + frontend/src/locales/en.ts | 14 ++- frontend/src/locales/ja.ts | 14 ++- 4 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 frontend/src/components/molecules/EventTransferLock.tsx diff --git a/frontend/src/components/molecules/EventTransferLock.tsx b/frontend/src/components/molecules/EventTransferLock.tsx new file mode 100644 index 00000000..f1e23f28 --- /dev/null +++ b/frontend/src/components/molecules/EventTransferLock.tsx @@ -0,0 +1,99 @@ +import { Box, Button, Flex, Grid, Spinner, Text } from "@chakra-ui/react"; +import { BigNumber } from "ethers"; +import { FC, useEffect } from "react"; +import { useIsMintLocked, useMintLock } from "src/hooks/useMintNFT"; +import AlertMessage from "../atoms/form/AlertMessage"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faLock, faLockOpen } from "@fortawesome/free-solid-svg-icons"; +import { useLocale } from "src/hooks/useLocale"; + +type Props = { + eventId: BigNumber; +}; + +const EventTransferLock: FC = ({ eventId }) => { + const { t } = useLocale(); + const { isMintLocked, isLoading, refetch } = useIsMintLocked(eventId); + + const { + lock, + isLoading: isLocking, + error, + isSuccess, + status, + } = useMintLock(eventId, !isMintLocked); + + useEffect(() => { + refetch(); + }, [status]); + + return ( + <> + {t.EVENT_TRANSFERLOCK_SETTING} + + {t.EVENT_TRANSFERLOCK_SETTING_DESC} + + {isLoading ? ( + + ) : ( + + + + + + + + + {isMintLocked + ? t.EVENT_ISNONTRANSFERABLE_TRUE + : t.EVENT_ISNONTRANSFERABLE_FALSE} + + + {isMintLocked + ? t.EVENT_ISNONTRANSFERABLE_TRUE_DESC + : t.EVENT_ISNONTRANSFERABLE_FALSE_DESC} + + + + + + + )} + {error && ( + + {(error as any).reason} + + )} + + ); +}; + +export default EventTransferLock; diff --git a/frontend/src/components/organisms/EventEditSection.tsx b/frontend/src/components/organisms/EventEditSection.tsx index 2d39f8a4..882282d7 100644 --- a/frontend/src/components/organisms/EventEditSection.tsx +++ b/frontend/src/components/organisms/EventEditSection.tsx @@ -3,6 +3,7 @@ import { FC, useMemo } from "react"; import { useOwnEventGroups } from "src/hooks/useEvent"; import { Event } from "types/Event"; import EventMintLock from "../molecules/EventMintLock"; +import EventTransferLock from "../molecules/EventTransferLock"; import ResetSecretPhrase from "../molecules/ResetSecretPhrase"; import { useLocale } from "src/hooks/useLocale"; @@ -41,6 +42,10 @@ const EventEditSection: FC = ({ event }) => { + + + + )} diff --git a/frontend/src/locales/en.ts b/frontend/src/locales/en.ts index eb3bc1a6..823455ce 100644 --- a/frontend/src/locales/en.ts +++ b/frontend/src/locales/en.ts @@ -94,12 +94,20 @@ export default { EVENT_ADMIN_MENU: "Admin Menu", EVENT_MINTLOCK_SETTING: "MintLock Setting", EVENT_MINTLOCK_SETTING_DESC: - "While locked, participants will not be able to Mint (receive proof of participation) for NFT.", - EVENT_ISLOCKED_TRUE: "Locked", - EVENT_ISLOCKED_FALSE: "Unlocked", + "While mint locked, participants will not be able to Mint (receive proof of participation) for NFT.", + EVENT_ISLOCKED_TRUE: "MintLocked", + EVENT_ISLOCKED_FALSE: "MintUnlocked", EVENT_ISLOCKED_TRUE_DESC: "NFT cannot be Minted.", EVENT_ISLOCKED_FALSE_DESC: "NFT can be Minted.", EVENT_MINTLOCK_FAIL: "Failed to change MintLock.", + EVENT_TRANSFERLOCK_SETTING: "TransferLock Setting", + EVENT_TRANSFERLOCK_SETTING_DESC: + "While transfer locked, participants will not be able to Transfer (send proof of participation) to others.", + EVENT_ISNONTRANSFERABLE_TRUE: "Non-Transferable", + EVENT_ISNONTRANSFERABLE_FALSE: "Transferable", + EVENT_ISNONTRANSFERABLE_TRUE_DESC: "NFT cannot be Transfer", + EVENT_ISNONTRANSFERABLE_FALSE_DESC: "NFT can be Transfer", + EVENT_TRANSFERLOCK_FAIL: "Failed to change TransferLock.", EVENT_ADMIN_SUBMIT: "Confirm", SECRET_PHRASE_RESET: "Reset Secret Phrase", SECRET_PHRASE_RESET_NEW: "New secret phrase", diff --git a/frontend/src/locales/ja.ts b/frontend/src/locales/ja.ts index bc3eb9ac..74989804 100644 --- a/frontend/src/locales/ja.ts +++ b/frontend/src/locales/ja.ts @@ -96,12 +96,20 @@ export default { EVENT_ADMIN_MENU: "管理者メニュー", EVENT_MINTLOCK_SETTING: "Mintロック設定", EVENT_MINTLOCK_SETTING_DESC: - "ロック中は、NFTのMint(参加証明の受け取り)ができなくなります。", - EVENT_ISLOCKED_TRUE: "ロック中", - EVENT_ISLOCKED_FALSE: "ロックされていません", + "Mintロック中は、NFTのMint(参加証明の受け取り)ができなくなります。", + EVENT_ISLOCKED_TRUE: "Mintロック中", + EVENT_ISLOCKED_FALSE: "Mintロックされていません", EVENT_ISLOCKED_TRUE_DESC: "NFTの配布をストップしています。", EVENT_ISLOCKED_FALSE_DESC: "NFTをMintすることが可能です。", EVENT_MINTLOCK_FAIL: "MintLock中にエラーが発生しました", + EVENT_TRANSFERLOCK_SETTING: "Transferロック設定", + EVENT_TRANSFERLOCK_SETTING_DESC: + "Transferロック中は、NFTのTransfer(参加証明の他者への送信)ができなくなります。", + EVENT_ISNONTRANSFERABLE_TRUE: "Transferロック中", + EVENT_ISNONTRANSFERABLE_FALSE: "Transferはロックされていません", + EVENT_ISNONTRANSFERABLE_TRUE_DESC: "NFTのTransferを制限しています。", + EVENT_ISNONTRANSFERABLE_FALSE_DESC: "NFTをTransferすることが可能です。", + EVENT_TRANSFERLOCK_FAIL: "TransferLock中にエラーが発生しました", SECRET_PHRASE_RESET: "あいことばのリセット", SECRET_PHRASE_RESET_NEW: "新しいあいことば", SECRET_PHRASE_RESET_NEW_PLACEHOLDER: "新しいあいことばを入力", From 0f89259486c854b10f1add8d6aa8bb65c4b018e8 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Thu, 7 Dec 2023 11:59:42 +0900 Subject: [PATCH 17/24] Add: non-transferable flag to createEventRecord tests --- hardhat/contracts/Event.sol | 5 +++++ hardhat/contracts/IMintNFT.sol | 5 +++++ hardhat/scripts/utils/create_test_events.ts | 11 ++++++++++- hardhat/test/EventManager.ts | 7 +++++++ hardhat/test/MintNFT.ts | 11 +++++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/hardhat/contracts/Event.sol b/hardhat/contracts/Event.sol index c7a09c69..6997a296 100644 --- a/hardhat/contracts/Event.sol +++ b/hardhat/contracts/Event.sol @@ -159,6 +159,7 @@ contract EventManager is OwnableUpgradeable { string memory _date, uint256 _mintLimit, bool _useMtx, + bool _isNtt, bytes32 _secretPhrase, IMintNFT.NFTAttribute[] memory _eventNFTAttributes ) external payable onlyGroupOwner(_groupId) whenNotPaused { @@ -196,6 +197,10 @@ contract EventManager is OwnableUpgradeable { _eventNFTAttributes ); + if (_isNtt) { + _mintNFT.changeNonTransferable(_newEventId, true); + } + eventIdsByGroupId[_groupId].push(_newEventId); groupIdByEventId[_newEventId] = _groupId; diff --git a/hardhat/contracts/IMintNFT.sol b/hardhat/contracts/IMintNFT.sol index a8406ecf..f5eab4be 100644 --- a/hardhat/contracts/IMintNFT.sol +++ b/hardhat/contracts/IMintNFT.sol @@ -18,6 +18,11 @@ interface IMintNFT { view returns (bool); + function changeNonTransferable( + uint256 _eventId, + bool _isNonTransferable + ) external; + function getApproved(uint256 tokenId) external view returns (address); function getRemainingNFTCount(uint256 _eventId) diff --git a/hardhat/scripts/utils/create_test_events.ts b/hardhat/scripts/utils/create_test_events.ts index 2efbdabf..6b3af272 100644 --- a/hardhat/scripts/utils/create_test_events.ts +++ b/hardhat/scripts/utils/create_test_events.ts @@ -4,7 +4,7 @@ import { ethers } from "hardhat"; // eslint-disable-next-line node/no-missing-import import { generateProof } from "../../test/helper/secret_phrase"; // eslint-disable-next-line node/no-missing-import -import { EventManager } from "../typechain"; +import { EventManager } from "../../typechain"; dotenv.config(); type eventParams = { @@ -15,6 +15,7 @@ type eventParams = { endTime: string; mintLimit: number; useMtx: boolean; + isNtt: boolean; secretPhrase?: string; attributes: any; }; @@ -43,6 +44,12 @@ class EventCreator { public async createEvents(_events: eventParams[]) { // create new group console.log("creating group..."); + + // undefinedのエラーが出たため、暫定的に追加してみました + if (!this.eventManager) { + throw new Error("EventManager is undefined"); + } + const datestring = new Date().toISOString().replace(/:/g, "-"); const txn1 = await this.eventManager.createGroup(`group-${datestring}`); await txn1.wait(); @@ -59,6 +66,7 @@ class EventCreator { event.date, event.mintLimit, event.useMtx, + event.isNtt, this.publicInputCalldata[0], event.attributes, { @@ -87,6 +95,7 @@ const main = async () => { endTime: "12:00", mintLimit: 1, useMtx: false, + isNtt: false, attributes: [ { metaDataURL: "ipfs://hogehoge/count0.json", diff --git a/hardhat/test/EventManager.ts b/hardhat/test/EventManager.ts index 34b4a217..7d4ae8ae 100644 --- a/hardhat/test/EventManager.ts +++ b/hardhat/test/EventManager.ts @@ -121,6 +121,7 @@ describe("EventManager", function () { "2022-07-3O", 100, false, + false, publicInputCalldata[0], attributes ) @@ -135,6 +136,7 @@ describe("EventManager", function () { "2022-07-3O", 100, false, + false, publicInputCalldata[0], attributes ); @@ -168,6 +170,7 @@ describe("EventManager", function () { "2022-08-01", 100, false, + false, publicInputCalldata[0], attributes ); @@ -192,6 +195,7 @@ describe("EventManager", function () { "2022-07-3O", 10, true, + false, publicInputCalldata[0], attributes, { value: ethers.utils.parseUnits(String(250000 * 10 * 1.33), "gwei") } @@ -215,6 +219,7 @@ describe("EventManager", function () { "2022-07-3O", 11 + i, true, + false, publicInputCalldata[0], attributes, { @@ -373,6 +378,7 @@ describe("EventManager", function () { "2023-07-3O", 100, false, + false, publicInputCalldata[0], attributes, { value: ethers.utils.parseUnits(String(250000 * 10 * 1.33), "gwei") } @@ -389,6 +395,7 @@ describe("EventManager", function () { "2023-07-3O", 100, false, + false, publicInputCalldata[0], attributes, { value: ethers.utils.parseUnits(String(250000 * 10 * 1.33), "gwei") } diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index d47cb1ee..a5d06aec 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -120,6 +120,7 @@ type eventGroupParams = { date: string; mintLimit: BigNumberish; useMtx: boolean; + isNtt: boolean; secretPhrase: BytesLike; eventNFTAttributes: { metaDataURL: string; @@ -150,6 +151,7 @@ const createEventRecord = async ( params.date, params.mintLimit, params.useMtx, + params.isNtt, params.secretPhrase, params.eventNFTAttributes ); @@ -189,6 +191,7 @@ describe("MintNFT", function () { "2022-07-3O", 10, false, + false, publicInputCalldata[0], attributes ); @@ -295,6 +298,7 @@ describe("MintNFT", function () { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: publicInputCalldata[0], eventNFTAttributes: attributes, }); @@ -307,6 +311,7 @@ describe("MintNFT", function () { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: publicInputCalldata[0], eventNFTAttributes: attributes, }); @@ -319,6 +324,7 @@ describe("MintNFT", function () { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: publicInputCalldata[0], eventNFTAttributes: attributes, }); @@ -471,6 +477,7 @@ describe("nft revolution", () => { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: publicInputCalldata[0], eventNFTAttributes: attributes, }); @@ -481,6 +488,7 @@ describe("nft revolution", () => { date: "2022-07-3O", mintLimit: 1, useMtx: false, + isNtt: false, secretPhrase: publicInputCalldata[0], eventNFTAttributes: attributes, }); @@ -587,6 +595,7 @@ describe("mint locked flag", () => { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: "0x10c7da1d87ac3a86d34053a76768cc39c581d469b68863a9fba17bcdaa048f98", eventNFTAttributes: attributes, @@ -658,6 +667,7 @@ describe("non transferable flag", () => { "2022-07-3O", 10, false, + false, correctProofCalldata, attributes ); @@ -745,6 +755,7 @@ describe("reset secret phrase", () => { date: "2022-07-3O", mintLimit: 10, useMtx: false, + isNtt: false, secretPhrase: correctProofCalldata, eventNFTAttributes: attributes, }, From 77c122cc843b8b838940aeffefb52b24db268c18 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:01:45 +0900 Subject: [PATCH 18/24] fix: variable name of non-transferable flag --- frontend/src/components/organisms/CreateEventForm.tsx | 10 +++++----- frontend/src/hooks/useEvent.ts | 2 +- frontend/types/Event.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/organisms/CreateEventForm.tsx b/frontend/src/components/organisms/CreateEventForm.tsx index 92234c78..7da4e975 100644 --- a/frontend/src/components/organisms/CreateEventForm.tsx +++ b/frontend/src/components/organisms/CreateEventForm.tsx @@ -47,7 +47,7 @@ interface EventFormData { secretPhrase: string; mintLimit: number; useMtx: "true" | "false"; - useNtt: "true" | "false"; + isNtt: "true" | "false"; nfts: NFT.NFTImage[]; } @@ -81,7 +81,7 @@ const CreateEventForm: FC = ({ address }) => { secretPhrase: "", mintLimit: 10, useMtx: undefined, - useNtt: undefined, + isNtt: undefined, nfts: [ { name: "", requiredParticipateCount: 0, description: "", image: "" }, ], @@ -116,7 +116,7 @@ const CreateEventForm: FC = ({ address }) => { secretPhrase: formData.secretPhrase, mintLimit: Number(formData.mintLimit), useMtx: formData.useMtx === "true", - useNtt: formData.useNtt === "false", + isNtt: formData.isNtt === "false", attributes: nftAttributes, }; await createEvent(params); @@ -445,7 +445,7 @@ const CreateEventForm: FC = ({ address }) => { = ({ address }) => { {t.EVENT_USE_NTT_TRUE} - {errors.useNtt?.message} + {errors.isNtt?.message} )} /> diff --git a/frontend/src/hooks/useEvent.ts b/frontend/src/hooks/useEvent.ts index df464b18..2baa36fd 100644 --- a/frontend/src/hooks/useEvent.ts +++ b/frontend/src/hooks/useEvent.ts @@ -214,7 +214,7 @@ export const useCreateEvent = (address: string) => { `${startDateTime}/${endDateTime}`, params.mintLimit, params.useMtx, - params.useNtt, + params.isNtt, proof?.publicInputCalldata[0], params.attributes, ], diff --git a/frontend/types/Event.ts b/frontend/types/Event.ts index 555e1ec5..3f030a8e 100644 --- a/frontend/types/Event.ts +++ b/frontend/types/Event.ts @@ -26,7 +26,7 @@ export namespace Event { secretPhrase: string; mintLimit: number; useMtx: boolean; - useNtt: boolean; + isNtt: boolean; attributes: { metaDataURL: string; requiredParticipateCount: number }[]; } } From 2ef2795486940117dbbaf23d132a40212798031b Mon Sep 17 00:00:00 2001 From: nfttakerun Date: Thu, 21 Dec 2023 12:38:53 +0900 Subject: [PATCH 19/24] update burn-by-user --- hardhat/contracts/MintNFT.sol | 29 ++++++-- hardhat/test/MintNFT.ts | 121 ++++++++++++++++++++++++++++------ 2 files changed, 124 insertions(+), 26 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index 124f7563..c94fe757 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -163,11 +163,23 @@ contract MintNFT is metaDataURL = specialMetaDataURL; } - nftMetaDataURL[_tokenIds.current()] = metaDataURL; - tokenIdsByEvent[_eventId].push(_tokenIds.current()); - _safeMint(_msgSender(), _tokenIds.current()); +// nftMetaDataURL[_tokenIds.current()] = metaDataURL; +// tokenIdsByEvent[_eventId].push(_tokenIds.current()); +// _safeMint(_msgSender(), _tokenIds.current()); _tokenIds.increment(); + + // 追記 + uint256 newTokenId = _tokenIds.current(); + + // トークンIDの重複チェック + require(!_exists(newTokenId), "Token already minted"); + + nftMetaDataURL[newTokenId] = metaDataURL; + tokenIdsByEvent[_eventId].push(newTokenId); + _safeMint(_msgSender(), newTokenId); + // 追記ここまで + emit MintedNFTAttributeURL(_msgSender(), metaDataURL); } @@ -286,15 +298,22 @@ contract MintNFT is return _nftAttributeRecords; } + // 新しいイベント定義 + // event BurnByOwner(uint256 indexed tokenId); + // event Burn(uint256 indexed tokenId); + event TokenBurned(uint256 tokenId); + // 既存の burn 関数の名前を変更 function burnByOwner(uint256 tokenId) public onlyOwner { - _burn(tokenId); + require(_exists(tokenId), "Token does not exist"); + _burn(tokenId); } // ユーザーが自身のNFTをバーンできるようにする新しい burn 関数 function burn(uint256 tokenId) public { - require(_isApprovedOrOwner(_msgSender(), tokenId), "caller is not owner nor approved"); + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); + emit TokenBurned(tokenId); } function tokenURI( diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index 31a3f459..92f7892e 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -204,8 +204,8 @@ describe("MintNFT", function () { .connect(organizer) .mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintNftTxn.wait(); - - const nftAttribute = await mintNFT.tokenURI(0); + + const nftAttribute = await mintNFT.tokenURI(1); // トークンIDを適切に指定 expect(nftAttribute).equal("ipfs://hogehoge/count0.json"); }); @@ -236,27 +236,106 @@ describe("MintNFT", function () { }); }); - describe("burn", () => { - it("success to burn", async () => { - const { proofCalldata } = await generateProof(); - const mintNftTxn = await mintNFT - .connect(participant2) - .mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); - await mintNftTxn.wait(); - - expect(await mintNFT.balanceOf(participant2.address)).equal(1); - - const tokenId = await mintNFT.tokenOfOwnerByIndex( - participant2.address, - 0 - ); + /** + * 零知識証明データを生成するダミー関数。 + * 実際の実装では、零知識証明スキームに基づいた正しい値を生成する必要あり + * @returns {uint256[24]} 零知識証明データの配列 + */ +async function generateProofData(): Promise<{ proofCalldata: uint256[24] }> { + const proofCalldata = []; + for (let i = 0; i < 24; i++) { + // ランダムな値で配列を埋める + proofCalldata.push(getRandomUint256()); + } + return { proofCalldata }; +} - // participant2がorganizerにトークンの操作を承認 - await mintNFT.connect(participant2).approve(organizer.address, tokenId); +/** + * ランダムな uint256 値を生成 + * この関数はダミーの値を生成するために使用 + * @returns {uint256} ランダムな値 + */ +function getRandomUint256(): uint256 { + // ここでは単純なランダム値を生成しているが、 + // 実際には適切な値を設定する必要あり + return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); +} + +// テストでの使用例 +const dummyProofData = generateProofData(); +console.log(dummyProofData); + +let proofCalldata; // proofCalldata を外部で宣言 + + beforeEach(async function () { + // proofCalldata の生成 + const proofData = await generateProofData(); + proofCalldata = proofData.inputs; // ここで proofCalldata に値を割り当てる + }); - // 承認後にburnを実行 - await mintNFT.connect(organizer).burn(tokenId); - expect(await mintNFT.balanceOf(participant2.address)).equal(0); + describe("burn function", function () { + it("should allow a token owner to burn their token", async function () { + // トークンをミントするための引数を準備 + const groupId = createdGroupId; // グループID + const eventId = createdEventIds[0]; // イベントID + const proofCalldata = await generateProof(); // 零知識証明データ + // トークンをミント + const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + await mintTx.wait(); + + // ミントされたトークンの数を確認 + expect(await mintNFT.balanceOf(participant1.address)).to.equal(1); + + // トークンをバーン + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); + await expect(mintNFT.connect(participant1).burn(tokenId)) + .to.emit(mintNFT, 'TokenBurned') + .withArgs(tokenId); + }); + + it("should fail if a non-owner tries to burn a token", async function () { + // トークンをミント + const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + await mintTx.wait(); + + // ミントされたトークンのIDを取得 + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); + + // 非所有者がトークンをバーンしようとする + await expect(mintNFT.connect(participant2).burn(tokenId)) + .to.be.revertedWith("caller is not owner nor approved"); + }); + }); + + describe("burnByOwner function", function () { + it("should allow the contract owner to burn any token", async function () { + // トークンをミント + const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + await mintTx.wait(); + + // ミントされたトークンのIDを取得 + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); + + // コントラクト所有者がトークンをバーン + await expect(mintNFT.connect(organizer).burnByOwner(tokenId)) + .to.emit(mintNFT, 'TokenBurned') + .withArgs(tokenId); + + // トークンがバーンされたことを確認 + expect(await mintNFT.balanceOf(participant1.address)).to.equal(0); + }); + + it("should fail if a non-contract owner tries to burn a token", async function () { + // トークンをミント + const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + await mintTx.wait(); + + // ミントされたトークンのIDを取得 + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); + + // 非コントラクト所有者がトークンをバーンしようとする + await expect(mintNFT.connect(participant2).burnByOwner(tokenId)) + .to.be.revertedWith("Ownable: caller is not the owner"); }); }); From 7a6b8f19e0c62de882bfad740a92469e437bcc9d Mon Sep 17 00:00:00 2001 From: yu23ki14 Date: Wed, 27 Dec 2023 17:41:07 +0900 Subject: [PATCH 20/24] tmp for deployment --- frontend/.sentryclirc | 3 ++ hardhat/scripts/helper/getAddresses.ts | 39 ++++++++++++++++++++ hardhat/scripts/helper/upgrade.ts | 31 ++-------------- hardhat/scripts/updateEventIdOfTokenId.ts | 45 +++++++++++++++++++---- 4 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 frontend/.sentryclirc create mode 100644 hardhat/scripts/helper/getAddresses.ts diff --git a/frontend/.sentryclirc b/frontend/.sentryclirc new file mode 100644 index 00000000..49b50a9a --- /dev/null +++ b/frontend/.sentryclirc @@ -0,0 +1,3 @@ + +[auth] +token=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 diff --git a/hardhat/scripts/helper/getAddresses.ts b/hardhat/scripts/helper/getAddresses.ts new file mode 100644 index 00000000..6c104e0f --- /dev/null +++ b/hardhat/scripts/helper/getAddresses.ts @@ -0,0 +1,39 @@ +import { network } from "hardhat"; + +export const mintNFTAddress = () => { + let contractAddress = ""; + switch (network.name) { + case "mumbai": + contractAddress = process.env.MUMBAI_MINTNFT_ADDRESS!; + break; + case "polygon": + contractAddress = process.env.POLYGON_MINTNFT_ADDRESS!; + break; + case "local": + contractAddress = process.env.LOCAL_MINTNFT_ADDRESS!; + break; + default: + break; + } + + return contractAddress; +}; + +export const eventManagerAddress = () => { + let contractAddress = ""; + switch (network.name) { + case "mumbai": + contractAddress = process.env.MUMBAI_EVENTMANAGER_ADDRESS!; + break; + case "polygon": + contractAddress = process.env.POLYGON_EVENTMANAGER_ADDRESS!; + break; + case "local": + contractAddress = process.env.LOCAL_EVENTMANAGER_ADDRESS!; + break; + default: + break; + } + + return contractAddress; +}; diff --git a/hardhat/scripts/helper/upgrade.ts b/hardhat/scripts/helper/upgrade.ts index 93dcffd8..43a7aab9 100644 --- a/hardhat/scripts/helper/upgrade.ts +++ b/hardhat/scripts/helper/upgrade.ts @@ -1,21 +1,9 @@ import { ethers, network, upgrades } from "hardhat"; import { MintNFT } from "../../typechain"; +import { eventManagerAddress, mintNFTAddress } from "./getAddresses"; export const upgradeMintNFT = async (params?: any[]) => { - let contractAddress = ""; - switch (network.name) { - case "mumbai": - contractAddress = process.env.MUMBAI_MINTNFT_ADDRESS!; - break; - case "polygon": - contractAddress = process.env.POLYGON_MINTNFT_ADDRESS!; - break; - case "local": - contractAddress = process.env.LOCAL_MINTNFT_ADDRESS!; - break; - default: - break; - } + let contractAddress = mintNFTAddress(); const MintNFTFactory = await ethers.getContractFactory("MintNFT"); const deployedMintNFT: MintNFT = (await upgrades.upgradeProxy( @@ -37,20 +25,7 @@ export const upgradeMintNFT = async (params?: any[]) => { }; export const upgradeEventManager = async (params?: any[]) => { - let contractAddress = ""; - switch (network.name) { - case "mumbai": - contractAddress = process.env.MUMBAI_EVENTMANAGER_ADDRESS!; - break; - case "polygon": - contractAddress = process.env.POLYGON_EVENTMANAGER_ADDRESS!; - break; - case "local": - contractAddress = process.env.LOCAL_EVENTMANAGER_ADDRESS!; - break; - default: - break; - } + let contractAddress = eventManagerAddress(); const EventManagerFactory = await ethers.getContractFactory("EventManager"); const deployedEventManager: any = await upgrades.upgradeProxy( diff --git a/hardhat/scripts/updateEventIdOfTokenId.ts b/hardhat/scripts/updateEventIdOfTokenId.ts index 038a03a3..aa631a1b 100644 --- a/hardhat/scripts/updateEventIdOfTokenId.ts +++ b/hardhat/scripts/updateEventIdOfTokenId.ts @@ -1,11 +1,12 @@ import { ethers } from "hardhat"; import { MintNFT, EventManager } from "../typechain"; import { BigNumber } from "ethers"; - -const MINT_NFT_ADDRESS = "0xC3894D90dF7EFCAe8CF34e300CF60FF29Db9a868"; -const EVENT_MANAGER_ADDRESS = "0x4fe4F50B719572b3a5A33516da59eC43F51F4A45"; +import { eventManagerAddress, mintNFTAddress } from "./helper/getAddresses"; async function main() { + const MINT_NFT_ADDRESS = mintNFTAddress(); + const EVENT_MANAGER_ADDRESS = eventManagerAddress(); + const MintNFTFactory = await ethers.getContractFactory("MintNFT"); const mintNFT = MintNFTFactory.attach(MINT_NFT_ADDRESS) as MintNFT; @@ -26,12 +27,42 @@ async function main() { eventIds.push(i); // @todo コントラクトをアップグレード後、以下のコメントアウトを外す - // const tokenIds: BigNumber[] = await mintNFT.getTokenIdsByEvent(i); + const tokenIds: BigNumber[] = await mintNFT.getTokenIdsByEvent(i); + console.log(tokenIds); - // tokenIdsArr.push(tokenIds.map((tokenId) => tokenId.toNumber())); + tokenIdsArr.push(tokenIds.map((tokenId) => tokenId.toNumber())); } - console.log("eventIds", eventIds); - console.log("tokenIdToEventIds", tokenIdsArr); + + // eventIds and tokenIdsArr length should be 100, create chunked array of eventIds and tokenIdsArr devide by 20 + const chunkedEventIds = eventIds.reduce((resultArray: any[], item, index) => { + const chunkIndex = Math.floor(index / 20); + + if (!resultArray[chunkIndex]) { + resultArray[chunkIndex] = []; + } + + resultArray[chunkIndex].push(item); + + return resultArray; + }, []); + + const chunkedTokenIdsArr = tokenIdsArr.reduce( + (resultArray: any[], item, index) => { + const chunkIndex = Math.floor(index / 20); + + if (!resultArray[chunkIndex]) { + resultArray[chunkIndex] = []; + } + + resultArray[chunkIndex].push(item); + + return resultArray; + }, + [] + ); + + console.log("chunkedEventIds", chunkedEventIds); + console.log("chunkedTokenIdsArr", chunkedTokenIdsArr); // @todo コントラクトをアップグレード後、以下のコメントアウトを外す // await (await mintNFT.setEventIdOfTokenIdsBatch(eventIds, tokenIdsArr)).wait(); From 162177dcbbc6a321366ae5c015fa80f6a7939ba3 Mon Sep 17 00:00:00 2001 From: yu23ki14 Date: Tue, 2 Jan 2024 23:05:20 +0900 Subject: [PATCH 21/24] modify initializer --- hardhat/contracts/Event.sol | 12 ++--- hardhat/contracts/MintNFT.sol | 10 +++-- hardhat/hardhat.config.ts | 13 ------ hardhat/scripts/updateEventIdOfTokenId.ts | 45 +++---------------- .../scripts/upgrades/v1.3.0/upgrade_stg.ts | 14 ++++-- 5 files changed, 30 insertions(+), 64 deletions(-) diff --git a/hardhat/contracts/Event.sol b/hardhat/contracts/Event.sol index dd175fec..bf7dc1f2 100644 --- a/hardhat/contracts/Event.sol +++ b/hardhat/contracts/Event.sol @@ -117,21 +117,23 @@ contract EventManager is OwnableUpgradeable { event CreateGroup(address indexed owner, uint256 groupId); event CreateEvent(address indexed owner, uint256 eventId); - // Currently, reinitializer(2) was executed as constructor. + // Currently, reinitializer(3) was executed as constructor. function initialize( + address _owner, address _relayerAddr, uint256 _mtxPrice, uint256 _maxMintLimit, address _operationControllerAddr - ) public reinitializer(2) { + ) public reinitializer(3) { __Ownable_init(); + _transferOwnership(_owner); if (_groupIds.current() == 0 && _eventRecordIds.current() == 0) { _groupIds.increment(); _eventRecordIds.increment(); } - setRelayerAddr(_relayerAddr); - setMtxPrice(_mtxPrice); - setMaxMintLimit(_maxMintLimit); + relayerAddr = _relayerAddr; + mtxPrice = _mtxPrice; + maxMintLimit = _maxMintLimit; operationControllerAddr = _operationControllerAddr; } diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index da9c1f3e..fab7a6a2 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -87,15 +87,17 @@ contract MintNFT is _; } - // Currently, reinitializer(4) was executed as constructor. + // Currently, reinitializer(5) was executed as constructor. function initialize( - MinimalForwarderUpgradeable trustedForwarder, + address _owner, + MinimalForwarderUpgradeable _trustedForwarder, address _secretPhraseVerifierAddr, address _operationControllerAddr - ) public reinitializer(4) { + ) public reinitializer(5) { __ERC721_init("MintRally", "MR"); __Ownable_init(); - __ERC2771Context_init(address(trustedForwarder)); + _transferOwnership(_owner); + __ERC2771Context_init(address(_trustedForwarder)); secretPhraseVerifierAddr = _secretPhraseVerifierAddr; operationControllerAddr = _operationControllerAddr; } diff --git a/hardhat/hardhat.config.ts b/hardhat/hardhat.config.ts index 2f382151..346df69e 100644 --- a/hardhat/hardhat.config.ts +++ b/hardhat/hardhat.config.ts @@ -13,19 +13,6 @@ import "hardhat-watcher"; dotenv.config(); -// This is a sample Hardhat task. To learn how to create your own go to -// https://hardhat.org/guides/create-task.html -task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { - const accounts = await hre.ethers.getSigners(); - - for (const account of accounts) { - console.log(account.address); - } -}); - -// You need to export an object to set up your config -// Go to https://hardhat.org/config/ to learn more - const config: HardhatUserConfig = { solidity: { version: "0.8.9", diff --git a/hardhat/scripts/updateEventIdOfTokenId.ts b/hardhat/scripts/updateEventIdOfTokenId.ts index aa631a1b..1cc238eb 100644 --- a/hardhat/scripts/updateEventIdOfTokenId.ts +++ b/hardhat/scripts/updateEventIdOfTokenId.ts @@ -33,49 +33,18 @@ async function main() { tokenIdsArr.push(tokenIds.map((tokenId) => tokenId.toNumber())); } - // eventIds and tokenIdsArr length should be 100, create chunked array of eventIds and tokenIdsArr devide by 20 - const chunkedEventIds = eventIds.reduce((resultArray: any[], item, index) => { - const chunkIndex = Math.floor(index / 20); - - if (!resultArray[chunkIndex]) { - resultArray[chunkIndex] = []; - } - - resultArray[chunkIndex].push(item); - - return resultArray; - }, []); - - const chunkedTokenIdsArr = tokenIdsArr.reduce( - (resultArray: any[], item, index) => { - const chunkIndex = Math.floor(index / 20); - - if (!resultArray[chunkIndex]) { - resultArray[chunkIndex] = []; - } - - resultArray[chunkIndex].push(item); - - return resultArray; - }, - [] - ); - - console.log("chunkedEventIds", chunkedEventIds); - console.log("chunkedTokenIdsArr", chunkedTokenIdsArr); - // @todo コントラクトをアップグレード後、以下のコメントアウトを外す - // await (await mintNFT.setEventIdOfTokenIdsBatch(eventIds, tokenIdsArr)).wait(); + await (await mintNFT.setEventIdOfTokenIdsBatch(eventIds, tokenIdsArr)).wait(); - // const lastEventIdOfTokenIds = tokenIdsArr[eventIds.length - 1]; + const lastEventIdOfTokenIds = tokenIdsArr[eventIds.length - 1]; - // console.log("lastEventIdOfTokenIds", lastEventIdOfTokenIds); + console.log("lastEventIdOfTokenIds", lastEventIdOfTokenIds); - // const eventIdOfTokenId = await mintNFT.getEventIdOfTokenId( - // lastEventIdOfTokenIds[lastEventIdOfTokenIds.length - 1] - // ); + const eventIdOfTokenId = await mintNFT.getEventIdOfTokenId( + lastEventIdOfTokenIds[lastEventIdOfTokenIds.length - 1] + ); - // console.log("check eventIdOfTokenId", eventIdOfTokenId.toNumber()); + console.log("check eventIdOfTokenId", eventIdOfTokenId.toNumber()); } main().catch((error) => { diff --git a/hardhat/scripts/upgrades/v1.3.0/upgrade_stg.ts b/hardhat/scripts/upgrades/v1.3.0/upgrade_stg.ts index d32757d5..aba3cb41 100644 --- a/hardhat/scripts/upgrades/v1.3.0/upgrade_stg.ts +++ b/hardhat/scripts/upgrades/v1.3.0/upgrade_stg.ts @@ -4,14 +4,20 @@ import { upgradeEventManager, upgradeMintNFT } from "../../helper/upgrade"; async function main() { if (network.name !== "mumbai") throw new Error("wrong network"); - await upgradeMintNFT(); - // [ + // await upgradeMintNFT([ + // process.env.MUMBAI_OWNER_ADDRESS!, // process.env.MUMBAI_FORWARDER_ADDRESS!, // process.env.MUMBAI_SECRETPHRASE_VERIFIER_ADDRESS!, // process.env.MUMBAI_OPERATION_CONTROLLER_ADDRESS!, - // ] + // ]); - // await upgradeEventManager(); + await upgradeEventManager([ + process.env.MUMBAI_OWNER_ADDRESS!, + process.env.MUMBAI_RELAYER_ADDRESS!, + 250000, + 1000000, + process.env.MUMBAI_OPERATION_CONTROLLER_ADDRESS, + ]); } main().catch((error) => { From a160eb8c00af281328099f0e3c5b88166deaf6f2 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sun, 21 Jan 2024 21:52:44 +0900 Subject: [PATCH 22/24] fix: test for _owner arg in initialize() --- hardhat/test/EventManager.ts | 40 +++++++++++++++++++++++++++++++----- hardhat/test/MintNFT.ts | 30 ++++++++++++++++++--------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/hardhat/test/EventManager.ts b/hardhat/test/EventManager.ts index 5f57f56b..1066b3bd 100644 --- a/hardhat/test/EventManager.ts +++ b/hardhat/test/EventManager.ts @@ -60,6 +60,7 @@ describe("EventManager", function () { const deployedMintNFT: any = await upgrades.deployProxy( MintNFTFactory, [ + organizer.address, "0xdCb93093424447bF4FE9Df869750950922F1E30B", secretPhraseVerifier.address, operationController.address, @@ -81,7 +82,12 @@ describe("EventManager", function () { ); const deployedEventManagerContract: any = await upgrades.deployProxy( eventManagerContractFactory, - [relayer.address, 250000, 1000000, operationController.address], + [ + organizer.address, + relayer.address, + 250000, + 1000000, + operationController.address], { initializer: "initialize", } @@ -476,7 +482,13 @@ describe("EventManager", function () { ); const deployedEventManagerContract: any = await upgrades.deployProxy( eventManagerContractFactory, - [relayer.address, 500000, 1000000, operationController.address], + [ + organizer.address, + relayer.address, + 500000, + 1000000, + operationController.address + ], { initializer: "initialize", } @@ -525,7 +537,13 @@ describe("EventManager", function () { ); const deployedEventManagerContract: any = await upgrades.deployProxy( eventManagerContractFactory, - [relayer.address, 500000, 1000000, operationController.address], + [ + organizer.address, + relayer.address, + 500000, + 1000000, + operationController.address + ], { initializer: "initialize", } @@ -594,7 +612,13 @@ describe("EventManager", function () { ); const deployedEventManagerContract: any = await upgrades.deployProxy( eventManagerContractFactory, - [relayer.address, 250000, 1000000, operationController.address], + [ + organizer.address, + relayer.address, + 250000, + 1000000, + operationController.address + ], { initializer: "initialize", } @@ -683,7 +707,13 @@ describe("EventManager", function () { ); const deployedEventManagerContract: any = await upgrades.deployProxy( eventManagerContractFactory, - [relayer.address, 250000, 1000000, operationController.address], + [ + organizer.address, + relayer.address, + 250000, + 1000000, + operationController.address + ], { initializer: "initialize", } diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index ca729ae6..1b1b3791 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -63,6 +63,7 @@ const deployOperationController = async () => { * @returns deployed mintNFT */ const deployMintNFT = async ( + deployer: SignerWithAddress, secretPhraseVerifier: SecretPhraseVerifier, operationController: OperationController ) => { @@ -70,6 +71,7 @@ const deployMintNFT = async ( const deployedMintNFT: any = await upgrades.deployProxy( MintNFTFactory, [ + deployer.address, "0xdCb93093424447bF4FE9Df869750950922F1E30B", secretPhraseVerifier.address, operationController.address, @@ -87,13 +89,20 @@ const deployMintNFT = async ( * @returns deployed eventManager */ const deployEventManager = async ( + deployer: SignerWithAddress, relayer: SignerWithAddress, operationController: OperationController ) => { const EventManager = await ethers.getContractFactory("EventManager"); const deployedEventManager: any = await upgrades.deployProxy( EventManager, - [relayer.address, 250000, 1000000, operationController.address], + [ + deployer.address, + relayer.address, + 250000, + 1000000, + operationController.address + ], { initializer: "initialize", } @@ -105,14 +114,15 @@ const deployEventManager = async ( * @param relayer address * @returns deployed contracts array */ -const deployAll = async (relayer: SignerWithAddress) => { +const deployAll = async (deployer: SignerWithAddress, relayer: SignerWithAddress) => { const secretPhraseVerifier = await deploySecretPhraseVerifier(); const operationController = await deployOperationController(); const mintNFT = await deployMintNFT( + deployer, secretPhraseVerifier, operationController ); - const eventManager = await deployEventManager(relayer, operationController); + const eventManager = await deployEventManager(deployer, relayer, operationController); await mintNFT.setEventManagerAddr(eventManager.address); await eventManager.setMintNFTAddr(mintNFT.address); return [secretPhraseVerifier, mintNFT, eventManager, operationController]; @@ -182,7 +192,7 @@ describe("MintNFT", function () { // generate proof const { publicInputCalldata } = await generateProof(); // Deploy all contracts - [, mintNFT, eventManager, operationController] = await deployAll(relayer); + [, mintNFT, eventManager, operationController] = await deployAll(organizer, relayer); // Create a Group and an Event await createGroup(eventManager, "First Group"); const groupsList = await eventManager.getGroups(); @@ -286,7 +296,7 @@ describe("MintNFT", function () { const { publicInputCalldata } = await generateProof(); // Deploy all contracts - [, mintNFT, eventManager] = await deployAll(relayer); + [, mintNFT, eventManager] = await deployAll(organizer, relayer); // Create a Group and an Event await createGroup(eventManager, "First Group"); @@ -555,7 +565,7 @@ describe("nft revolution", () => { // generate proof const { publicInputCalldata } = await generateProof(); - [, mintNFT, eventManager] = await deployAll(relayer); + [, mintNFT, eventManager] = await deployAll(organizer, relayer); // Create a Group and an Event await createGroup(eventManager, "First Group"); @@ -688,7 +698,7 @@ describe("bulk mint by event owner", () => { // generate proof const { publicInputCalldata } = await generateProof(); - [, mintNFT, eventManager] = await deployAll(relayer); + [, mintNFT, eventManager] = await deployAll(organizer, relayer); // Create a Group and an Event await createGroup(eventManager, "First Group"); @@ -810,7 +820,7 @@ describe("mint locked flag", () => { before(async () => { [organizer, participant1, relayer] = await ethers.getSigners(); - [, mintNFT, eventManager, operationController] = await deployAll(relayer); + [, mintNFT, eventManager, operationController] = await deployAll(organizer, relayer); // Create a Group and an Event await createGroup(eventManager, "First Group", organizer); @@ -914,7 +924,7 @@ describe("non transferable flag", () => { // generate proof const { publicInputCalldata, proofCalldata } = await generateProof(); - [, mintNFT, eventManager, operationController] = await deployAll(relayer); + [, mintNFT, eventManager, operationController] = await deployAll(organizer, relayer); correctProofCalldata = publicInputCalldata[0]; // Create a Group and an Event @@ -999,7 +1009,7 @@ describe("reset secret phrase", () => { before(async () => { [organizer, participant1, relayer] = await ethers.getSigners(); // deploy all contracts - [, mintNFT, eventManager, operationController] = await deployAll(relayer); + [, mintNFT, eventManager, operationController] = await deployAll(organizer, relayer); // generate proof const { publicInputCalldata } = await generateProof(); correctProofCalldata = publicInputCalldata[0]; From c342f9a0cf4879e2f02b4aafc244ed301c3b0fb6 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Sun, 21 Jan 2024 22:28:02 +0900 Subject: [PATCH 23/24] fix: proofCalldata in MintNFT.ts --- hardhat/test/MintNFT.ts | 42 ++++------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index 00f75366..46eb704d 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -245,49 +245,12 @@ describe("MintNFT", function () { }); }); - /** - * 零知識証明データを生成するダミー関数。 - * 実際の実装では、零知識証明スキームに基づいた正しい値を生成する必要あり - * @returns {uint256[24]} 零知識証明データの配列 - */ -async function generateProofData(): Promise<{ proofCalldata: uint256[24] }> { - const proofCalldata = []; - for (let i = 0; i < 24; i++) { - // ランダムな値で配列を埋める - proofCalldata.push(getRandomUint256()); - } - return { proofCalldata }; -} - -/** - * ランダムな uint256 値を生成 - * この関数はダミーの値を生成するために使用 - * @returns {uint256} ランダムな値 - */ -function getRandomUint256(): uint256 { - // ここでは単純なランダム値を生成しているが、 - // 実際には適切な値を設定する必要あり - return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); -} - -// テストでの使用例 -const dummyProofData = generateProofData(); -console.log(dummyProofData); - -let proofCalldata; // proofCalldata を外部で宣言 - - beforeEach(async function () { - // proofCalldata の生成 - const proofData = await generateProofData(); - proofCalldata = proofData.inputs; // ここで proofCalldata に値を割り当てる - }); - describe("burn function", function () { it("should allow a token owner to burn their token", async function () { + const { proofCalldata } = await generateProof(); // トークンをミントするための引数を準備 const groupId = createdGroupId; // グループID const eventId = createdEventIds[0]; // イベントID - const proofCalldata = await generateProof(); // 零知識証明データ // トークンをミント const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); @@ -303,6 +266,7 @@ let proofCalldata; // proofCalldata を外部で宣言 }); it("should fail if a non-owner tries to burn a token", async function () { + const { proofCalldata } = await generateProof(); // トークンをミント const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); @@ -318,6 +282,7 @@ let proofCalldata; // proofCalldata を外部で宣言 describe("burnByOwner function", function () { it("should allow the contract owner to burn any token", async function () { + const { proofCalldata } = await generateProof(); // トークンをミント const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); @@ -335,6 +300,7 @@ let proofCalldata; // proofCalldata を外部で宣言 }); it("should fail if a non-contract owner tries to burn a token", async function () { + const { proofCalldata } = await generateProof(); // トークンをミント const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); From 4eec063e0da7d7b91ca74b49838e59b322c7c2a3 Mon Sep 17 00:00:00 2001 From: yawn <69970183+yawn-c111@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:19:59 +0900 Subject: [PATCH 24/24] update: event and function name and tests --- hardhat/contracts/MintNFT.sol | 14 +++---- hardhat/test/MintNFT.ts | 74 +++++++++++++++-------------------- 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/hardhat/contracts/MintNFT.sol b/hardhat/contracts/MintNFT.sol index c4e6aadc..2da323d0 100644 --- a/hardhat/contracts/MintNFT.sol +++ b/hardhat/contracts/MintNFT.sol @@ -69,6 +69,8 @@ contract MintNFT is event ResetSecretPhrase(address indexed executor, uint256 indexed eventId); event NonTransferable(uint256 indexed eventId, bool isNonTransferable); event DroppedNFTs(address indexed executor, uint256 indexed eventId); + event BurnByAdmin(uint256 indexed tokenId, address indexed admin); + event Burn(uint256 indexed tokenId, address indexed owner); modifier onlyCollaboratorAccess(uint256 _eventId) { IEventManager eventManager = IEventManager(eventManagerAddr); @@ -342,22 +344,16 @@ contract MintNFT is return _nftAttributeRecords; } - // 新しいイベント定義 - // event BurnByOwner(uint256 indexed tokenId); - // event Burn(uint256 indexed tokenId); - event TokenBurned(uint256 tokenId); - - // 既存の burn 関数の名前を変更 - function burnByOwner(uint256 tokenId) public onlyOwner { + function burnByAdmin(uint256 tokenId) public onlyOwner { require(_exists(tokenId), "Token does not exist"); _burn(tokenId); + emit BurnByAdmin(tokenId, _msgSender()); } - // ユーザーが自身のNFTをバーンできるようにする新しい burn 関数 function burn(uint256 tokenId) public { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); - emit TokenBurned(tokenId); + emit Burn(tokenId, _msgSender()); } function tokenURI( diff --git a/hardhat/test/MintNFT.ts b/hardhat/test/MintNFT.ts index e1d31530..fbe17892 100644 --- a/hardhat/test/MintNFT.ts +++ b/hardhat/test/MintNFT.ts @@ -182,11 +182,13 @@ describe("MintNFT", function () { let organizer: SignerWithAddress; let participant1: SignerWithAddress; - let relayer: SignerWithAddress; let participant2: SignerWithAddress; + let participant3: SignerWithAddress; + let participant4: SignerWithAddress; + let relayer: SignerWithAddress; before(async () => { - [organizer, participant1, relayer, participant2] = + [organizer, participant1, participant2, participant3, participant4, relayer] = await ethers.getSigners(); // generate proof @@ -222,7 +224,7 @@ describe("MintNFT", function () { .mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintNftTxn.wait(); - const nftAttribute = await mintNFT.tokenURI(1); // トークンIDを適切に指定 + const nftAttribute = await mintNFT.tokenURI(0); expect(nftAttribute).equal("ipfs://hogehoge/count0.json"); expect(await mintNFT.getEventIdOfTokenId(0)).equal(createdEventIds[0]); @@ -258,68 +260,56 @@ describe("MintNFT", function () { describe("burn function", function () { it("should allow a token owner to burn their token", async function () { const { proofCalldata } = await generateProof(); - // トークンをミントするための引数を準備 - const groupId = createdGroupId; // グループID - const eventId = createdEventIds[0]; // イベントID - // トークンをミント + const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); - - // ミントされたトークンの数を確認 + expect(await mintNFT.balanceOf(participant1.address)).to.equal(1); - - // トークンをバーン + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); await expect(mintNFT.connect(participant1).burn(tokenId)) - .to.emit(mintNFT, 'TokenBurned') - .withArgs(tokenId); + .to.emit(mintNFT, 'Burn') + .withArgs(tokenId, participant1.address); }); it("should fail if a non-owner tries to burn a token", async function () { const { proofCalldata } = await generateProof(); - // トークンをミント - const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + + const mintTx = await mintNFT.connect(participant2).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); - - // ミントされたトークンのIDを取得 - const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); - - // 非所有者がトークンをバーンしようとする - await expect(mintNFT.connect(participant2).burn(tokenId)) + + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant2.address, 0); + + await expect(mintNFT.connect(participant1).burn(tokenId)) .to.be.revertedWith("caller is not owner nor approved"); }); }); - describe("burnByOwner function", function () { + describe("burnByAdmin function", function () { it("should allow the contract owner to burn any token", async function () { const { proofCalldata } = await generateProof(); - // トークンをミント - const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + + const mintTx = await mintNFT.connect(participant3).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); - - // ミントされたトークンのIDを取得 - const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); - - // コントラクト所有者がトークンをバーン - await expect(mintNFT.connect(organizer).burnByOwner(tokenId)) - .to.emit(mintNFT, 'TokenBurned') - .withArgs(tokenId); - - // トークンがバーンされたことを確認 + + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant3.address, 0); + + await expect(mintNFT.connect(organizer).burnByAdmin(tokenId)) + .to.emit(mintNFT, 'BurnByAdmin') + .withArgs(tokenId, organizer.address); + expect(await mintNFT.balanceOf(participant1.address)).to.equal(0); }); it("should fail if a non-contract owner tries to burn a token", async function () { const { proofCalldata } = await generateProof(); - // トークンをミント - const mintTx = await mintNFT.connect(participant1).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); + + const mintTx = await mintNFT.connect(participant4).mintParticipateNFT(createdGroupId, createdEventIds[0], proofCalldata); await mintTx.wait(); - - // ミントされたトークンのIDを取得 - const tokenId = await mintNFT.tokenOfOwnerByIndex(participant1.address, 0); - - // 非コントラクト所有者がトークンをバーンしようとする - await expect(mintNFT.connect(participant2).burnByOwner(tokenId)) + + const tokenId = await mintNFT.tokenOfOwnerByIndex(participant4.address, 0); + + await expect(mintNFT.connect(participant4).burnByAdmin(tokenId)) .to.be.revertedWith("Ownable: caller is not the owner"); }); });