From 4086ad1eee586dd6958de4df2cc91676b78cff8b Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 30 Aug 2023 08:31:47 +0900 Subject: [PATCH 01/17] add comment --- contract/contracts/LocalNounsToken.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index ad2958b3..b3234be7 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -109,6 +109,10 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { administratorsAddress = _admin; } + /** + * @param _tokenId the token id for put on the trade list. + * @param _prefectures prefectures that you want to trade. if you don't want specific prefecture, you don't need to set. + */ function putTradeLocalNoun(uint256 _tokenId, uint256[] memory _prefectures) public { for (uint256 i = 0; i < _prefectures.length; i++) { require(_prefectures[i] > 0 && _prefectures[i] <= 47, 'incorrect prefecutre id'); @@ -134,6 +138,7 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { } function executeTradeLocalNoun(uint256 _myTokenId, uint256 _targetTokenId) public { + // tradePrefectureがない場合は、希望都道府県がないためチェック不要 if (tradePrefecture[_targetTokenId].length > 0) { uint256 myTokenIdPrefecture = assetProvider2.getPrefectureId(_myTokenId); bool isIncludesList = false; From db0f5a7a642e717338e41466a2b3d5e4778a96df Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 08:23:53 +0900 Subject: [PATCH 02/17] =?UTF-8?q?mintSelectedPrefecture=E3=81=AB=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E6=8C=87=E5=AE=9A=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 14 +- .../contracts/localNouns/LocalNounsMinter.sol | 47 +- .../interfaces/ILocalNounsToken.sol | 2 +- contract/test/image-local-data2.json | 440 ++++++++++++++++++ contract/test/localNouns.ts | 149 +++--- .../localNounsDescriptor_localhost.ts | 2 +- .../addresses/localNounsDescriptor_mumbai.ts | 2 +- .../addresses/localNounsMinter_localhost.ts | 2 +- .../addresses/localNounsMinter_mumbai.ts | 2 +- .../addresses/localNounsProvider_localhost.ts | 2 +- .../addresses/localNounsProvider_mumbai.ts | 2 +- .../addresses/localNounsToken_localhost.ts | 2 +- src/utils/addresses/localNounsToken_mumbai.ts | 2 +- src/utils/addresses/localseeder_localhost.ts | 2 +- src/utils/addresses/localseeder_mumbai.ts | 2 +- .../addresses/nftDescriptor_localhost.ts | 3 + src/utils/addresses/nftDescriptor_mumbai.ts | 2 +- .../addresses/nounsDescriptor_localhost.ts | 3 + src/utils/addresses/nounsDescriptor_mumbai.ts | 2 +- src/utils/addresses/nounsSeeder_localhost.ts | 3 + src/utils/addresses/nounsSeeder_mumbai.ts | 2 +- 21 files changed, 606 insertions(+), 81 deletions(-) create mode 100644 contract/test/image-local-data2.json create mode 100644 src/utils/addresses/nftDescriptor_localhost.ts create mode 100644 src/utils/addresses/nounsDescriptor_localhost.ts create mode 100644 src/utils/addresses/nounsSeeder_localhost.ts diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index b3234be7..abc8b21a 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -67,12 +67,16 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { ); } - function mintSelectedPrefecture(address _to, uint256 _prefectureId) public virtual returns (uint256 tokenId) { + function mintSelectedPrefecture( + address _to, + uint256 _prefectureId, + uint256 _amount + ) public virtual returns (uint256 tokenId) { require(msg.sender == minter, 'Sender is not the minter'); - assetProvider2.mint(_prefectureId, _nextTokenId()); - - _safeMint(_to, 1); - + for (uint256 i = 0; i < _amount; i++) { + assetProvider2.mint(_prefectureId, _nextTokenId()); + } + _safeMint(_to, _amount); return _nextTokenId() - 1; } diff --git a/contract/contracts/localNouns/LocalNounsMinter.sol b/contract/contracts/localNouns/LocalNounsMinter.sol index 18ec97e9..e7a473bf 100644 --- a/contract/contracts/localNouns/LocalNounsMinter.sol +++ b/contract/contracts/localNouns/LocalNounsMinter.sol @@ -23,23 +23,56 @@ import './interfaces/ILocalNounsToken.sol'; contract LocalNounsMinter is Ownable { ILocalNounsToken public token; + uint256 public mintPriceForSpecified = 0.03 ether; + uint256 public mintPriceForNotSpecified = 0.01 ether; + + uint256 public constant mintMax = 1200; + + mapping(address => uint256) public preferentialPurchacedCount; + + enum SalePhase { + Locked, + PreSale, + PublicSale + } + + SalePhase public phase = SalePhase.Locked; // セールフェーズ + + address public administratorsAddress; // 運営ウォレット + constructor(ILocalNounsToken _token) { token = _token; + administratorsAddress = msg.sender; } function setLocalNounsToken(ILocalNounsToken _token) external onlyOwner { token = _token; } - function mintSelectedPrefecture(uint256 _prefectureId) public payable returns (uint256 tokenId) { - return token.mintSelectedPrefecture(msg.sender, _prefectureId); + function setMintPriceForSpecified(uint256 _price) external onlyOwner { + mintPriceForSpecified = _price; } - function mintSelectedPrefectureBatch( - uint256[] memory _prefectureId, - uint256[] memory _amount - ) public payable returns (uint256 tokenId) { + function setMintPriceForNotSpecified(uint256 _price) external onlyOwner { + mintPriceForNotSpecified = _price; + } + + function setPhase(SalePhase _phase) external onlyOwner { + phase = _phase; + } + + function setAdministratorsAddress(address _admin) external onlyOwner { + administratorsAddress = _admin; + } + + function mintSelectedPrefecture(uint256 _prefectureId, uint256 _amount) public payable returns (uint256 tokenId) { + require(phase != SalePhase.Locked, 'Sale is locked'); + return token.mintSelectedPrefecture(msg.sender, _prefectureId, _amount); + } - return token.mintSelectedPrefectureBatch(msg.sender, _prefectureId, _amount); + function withdraw() external payable onlyOwner { + require(administratorsAddress != address(0), "administratorsAddress shouldn't be 0"); + (bool sent, ) = payable(administratorsAddress).call{ value: address(this).balance }(''); + require(sent, 'failed to move fund to administratorsAddress contract'); } } diff --git a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol index 45c370f4..c9330d17 100644 --- a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol +++ b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol @@ -18,7 +18,7 @@ pragma solidity ^0.8.6; interface ILocalNounsToken { - function mintSelectedPrefecture(address to, uint256 prefectureId) external returns (uint256 tokenId); + function mintSelectedPrefecture(address to, uint256 prefectureId, uint256 _amount) external returns (uint256 tokenId); function mintSelectedPrefectureBatch( address _to, diff --git a/contract/test/image-local-data2.json b/contract/test/image-local-data2.json new file mode 100644 index 00000000..a2e18ce7 --- /dev/null +++ b/contract/test/image-local-data2.json @@ -0,0 +1,440 @@ +{ + "bgcolors": [ + "d5d7e1", + "e1d7d5" + ], + "palette": [ + "", + "ffffff", + "c5b9a1", + "cfc2ab", + "63a0f9", + "807f7e", + "caeff9", + "5648ed", + "5a423f", + "b9185c", + "b87b11", + "fffdf2", + "4b4949", + "343235", + "1f1d29", + "068940", + "867c1d", + "ae3208", + "9f21a0", + "f98f30", + "fe500c", + "d26451", + "fd8b5b", + "5a65fa", + "d22209", + "e9265c", + "c54e38", + "80a72d", + "4bea69", + "34ac80", + "eed811", + "62616d", + "ff638d", + "8bc0c5", + "c4da53", + "000000", + "f3322c", + "ffae1a", + "ffc110", + "505a5c", + "ffef16", + "fff671", + "fff449", + "db8323", + "df2c39", + "f938d8", + "5c25fb", + "2a86fd", + "45faff", + "38dd56", + "ff3a0e", + "d32a09", + "903707", + "6e3206", + "552e05", + "e8705b", + "f38b7c", + "e4a499", + "667af9", + "648df9", + "7cc4f2", + "97f2fb", + "a3efd0", + "87e4d9", + "71bde4", + "ff1a0b", + "f78a18", + "2b83f6", + "d62149", + "834398", + "ffc925", + "d9391f", + "bd2d24", + "ff7216", + "254efb", + "e5e5de", + "00a556", + "c5030e", + "abf131", + "fb4694", + "e7a32c", + "fff0ee", + "009c59", + "0385eb", + "00499c", + "e11833", + "26b1f3", + "fff0be", + "d8dadf", + "d7d3cd", + "1929f4", + "eab118", + "0b5027", + "f9f5cb", + "cfc9b8", + "feb9d5", + "f8d689", + "5d6061", + "76858b", + "757576", + "ff0e0e", + "0adc4d", + "fdf8ff", + "70e890", + "f7913d", + "ff1ad2", + "ff82ad", + "535a15", + "fa6fe2", + "ffe939", + "ab36be", + "adc8cc", + "604666", + "f20422", + "abaaa8", + "4b65f7", + "a19c9a", + "58565c", + "da42cb", + "027c92", + "cec189", + "909b0e", + "74580d", + "027ee6", + "b2958d", + "efad81", + "7d635e", + "eff2fa", + "6f597a", + "d4b7b2", + "d18687", + "cd916d", + "6b3f39", + "4d271b", + "85634f", + "f9f4e6", + "f8ddb0", + "b92b3c", + "d08b11", + "257ced", + "a3baed", + "5fd4fb", + "c16710", + "a28ef4", + "3a085b", + "67b1e3", + "1e3445", + "ffd067", + "962236", + "769ca9", + "5a6b7b", + "7e5243", + "a86f60", + "8f785e", + "cc0595", + "42ffb0", + "d56333", + "b8ced2", + "b91b43", + "f39713", + "e8e8e2", + "ec5b43", + "235476", + "b2a8a5", + "d6c3be", + "49b38b", + "fccf25", + "f59b34", + "375dfc", + "99e6de", + "27a463", + "554543", + "b19e00", + "d4a015", + "9f4b27", + "f9e8dd", + "6b7212", + "9d8e6e", + "4243f8", + "fa5e20", + "f82905", + "555353", + "876f69", + "410d66", + "552d1d", + "f71248", + "fee3f3", + "c16923", + "2b2834", + "0079fc", + "d31e14", + "f83001", + "8dd122", + "fffdf4", + "ffa21e", + "e4afa3", + "fbc311", + "aa940c", + "eedc00", + "fff006", + "9cb4b8", + "a38654", + "ae6c0a", + "2bb26b", + "e2c8c0", + "f89865", + "f86100", + "dcd8d3", + "049d43", + "d0aea9", + "f39d44", + "eeb78c", + "f9f5e9", + "5d3500", + "c3a199", + "aaa6a4", + "caa26a", + "fde7f5", + "fdf008", + "fdcef2", + "f681e6", + "018146", + "d19a54", + "9eb5e1", + "f5fcff", + "3f9323", + "00fcff", + "4a5358", + "fbc800", + "d596a6", + "ffb913", + "e9ba12", + "767c0e", + "f9f6d1", + "d29607", + "f8ce47", + "395ed1", + "ffc5f0", + "cbc1bc", + "d4cfc0" + ], + "images": { + "heads": [ + { + "filename": "101-head-01-hokkaido-heads", + "data": "0x00021f1a0109000154140008000354130006000154010004541200090004541100090005541000090006540e000154090007540c000254090009540600015403000154010009000c540200025402000154020009000f540200015403000800105406000700125404000154070012540100025402000300025403001254040004000254010011540600040010540a00030010540b00020010540c000100035401000354020007540d000100025403000154040005540e00010002540a0003540e00020003540a0001540e0002000454180001000354010001541800010002541b00" + }, + { + "filename": "102-head-02-aomori-heads", + "data": "0x00021b17040d00015409000c0003540400015403000c0005540100025403000c00085403000b00055401000254040005000154010001540300045402000254040004000554020001540500025404000500045407000354040006000454020001540300035404000500055402000254020003540400050005540200035401000354040005000f54030004001054030002001254030001001354030015540200010015540100010005540100055401000a5401000154060003540300085401000e0004540100015403000e00025407000e0001540800" + }, + { + "filename": "103-head-03-iwate-heads", + "data": "0x00021717090900015404000600055403000200015401000754030002000a54020001000a54030001000b54020002000b5401000d54010001000c5401000d54010001000d5401000d540d5401000e540c54020001000c5401000c54020001000c54010001000a540300020006540600040004540600050001540800" + }, + { + "filename": "104-head-04-miyagi-heads", + "data": "0x00031c1808060001540a00025401000500045408000254010003000954040002540100015404000754030001540100025402000500085401000454020004000d54030003000f54020004000d54030003000f54020004000d54030004000d54010001540100030008540100015403000254020003000954050001540200020009540900020008540a00020008540a00010008540b0009540b0009540b00020007540b00050003540c00060002540c00" + }, + { + "filename": "105-head-05-akita-heads", + "data": "0x00031617090300055403000254040009540400095403000a5403000954010002000a540100015401000a5401000d5403000854020004000854010004000754020004000754020004000754020004000654030003000754030003000754030002000954020002000a540100040007540200050007540100070003540300" + }, + { + "filename": "106-head-06-yamagata-heads", + "data": "0x000318180a05000254070005000454050004000754030004000854020004000954010003000b5402000c5401000d5401000c5401000e5402000c5402000c5404000954010004000854020004000854020002000a540200020009540300020008540400020007540500020007540500030006540500060003540500" + }, + { + "filename": "107-head-07-fukushima-heads", + "data": "0x00051b17030e00035407000e0006540200015401000800035403000654020002540700055402000a5406001254050013540500135403001554185401001754010017541854020016540200075402000d540100065406000a540100010003540a00095401000e00095401000f000354010002540300100001540700" + }, + { + "filename": "108-head-08-ibaraki-heads", + "data": "0x0003191807090001540300015404000900025401000554010009000754020009000754020008000854020008000754030008000754030008000654040008000654040007000754040004000a54040002000b54050002000b5405000e5404000e54040002000c54040003000c54030003000c54030004000c5402000700045403000254020010000154010011000154" + }, + { + "filename": "109-head-09-tochigi-heads", + "data": "0x000418160709000454040007000854020005000b54010003000d54010002000e54010001000f54010002000e54010001000f54010001001054105401001054010003000d54010002000e54010002000e54010002000d54020001000e54020002000954010001540400030006540800060003540800" + }, + { + "filename": "110-head-10-gunma-heads", + "data": "0x00021c17060c00015409000a00035409000a000454080009000854050009000754060007000a54050005000b54060002000e54060001000f5406000100105405001254040011540500115405000100025401000d54050004000c54060004000e5404000300095401000754020004000754070003540100030008540a000154040005540d00040003540f00040002541000" + }, + { + "filename": "111-head-11-saitama-heads", + "data": "0x00071c1403080002540f00080005540c000700095401000254060007000e54040005001154030003001354030001001654020017540200185401001854010001000554010012540300025405000f540d000c540e000254020002540500" + }, + { + "filename": "112-head-12-chiba-heads", + "data": "0x000219170801541000010001540f00010002540e000200035404000354050002000c54030001000e5402000100105402000b540400020001540100085405000500065406000400065407000300075407000200085407000100095407000a540700020008540700010009540700010008540800010004540c00020002540d0004540d00010002540e00" + }, + { + "filename": "113-head-13-tokyo-heads", + "data": "0x00091c140301000254160007541200010009540f0001000a540300025402000654010002001654010003001654040015540600135407000f54010001540100080006540300055403000c0003540400045402000d000154070002540200" + }, + { + "filename": "114-head-14-kanagawa-heads", + "data": "0x00041d160306000254120007000254110007000354060004540600070007540300055404000600095402000754020006000a54010009540400155401000200145404000100165403001654040002001454040002001454040003000c5401000654040003000754090004540300020006540c0005540100020005540d0004540200020005540e0004540100030005540c000254040004000254010001540d0002540300" + }, + { + "filename": "115-head-15-niigata-heads", + "data": "0x00021b170413000254020013000254020009000154090004540800015409000554070002540900035402000700035407000454020008000254050006540200070002540400095401000c00095402000c00095402000c00085403000b00095403000a000854050009000754070008000954060007000954070004000d54060002000f540600085402000554010001540600010002540100035403000454090001000154090002540a000b0001540b00" + }, + { + "filename": "116-head-16-toyama-heads", + "data": "0x00051b17050300045409000454020002000454090006540100020003540a00065401000100055408000854010007540600085401001554165401001554165401001554010014540100010014540100010013540200145402000b54010001540100065402000854080003540300010006540f0001000154030002540f00050001541000" + }, + { + "filename": "117-head-17-ishikawa-heads", + "data": "0x00031517080a0003540700055401000600065401000600045403000500035405000500035401000154030006000454030006000454030007000154050006000254050006000154060005000354050005000254060004000454050003000454060002000554060001000754050007540600010007540500020005540600050002540600" + }, + { + "filename": "118-head-18-fukui-heads", + "data": "0x00041a18020c0001540b000b0003540a000c00035409000b0005540100025405000a000a5404000a000d54010009000d54020009000d5402000a000d5401000a000e540b000d540c00035401000254060009000154010004540900090001540100015401000254090006000154020003540c00070005540c000100015401000154010006540d00025401000554010001540e0008541000010007541000020004541200" + }, + { + "filename": "119-head-19-yamanashi-heads", + "data": "0x00051a1806040002540e00030003540e00010001540100065401000354070001000f5404001054040001001054030012540200145401001254010001001354020012540200115401000100105403000200055401000754050001000654030005540500010006540d00030003540e00040002540e00040003540d00050002540d00" + }, + { + "filename": "120-head-20-nagano-heads", + "data": "0x000319170b0b000254010006000154020005540500095405000754020005000754020004000754030003000854030003000a54010003000954020002000b54010002000a54020003000a5401000200085401000354095404000154010008540500020006540600020007540500030005540600030005540600020006540600020004540800" + }, + { + "filename": "121-head-21-gifu-heads", + "data": "0x00031817060c0001540100025402000b000754070002540100085407000a54010007000a54010006000a54020006000b54010006000a5402000700085403000800065404000100025401000b54030001000f5402001054020001001054010002001054020010540300055402000754010003000454040006540100020004540600015401000254020002000154010002540c00050001540c00" + }, + { + "filename": "122-head-22-shizuoka-heads", + "data": "0x00031d14050a0001540d00090002540d000a0001540d00090002540400015408000a000154040003540200035401000800035401000154020008540100060007540200075402000500095401000754020005000c540200055404000c5404000354010003000c540600035403000d5402000554010002000c54040006540c54070005540d540500055401000c5407000454010004000254020003540700045402000a000154080002540300" + }, + { + "filename": "123-head-23-aichi-heads", + "data": "0x00041c170505000154110001000154010004541000010007540f0001000854020002540300015406000e54010002540200025402001754175401001554010001000354010011540100020001540100115402000400105403000300115403000300035401000d540300020001540100015401000d5404000400015402000a540600030002540500015402000354070004000254060001540100025407000b000554070007000154010005540900060005540c00" + }, + { + "filename": "124-head-24-mie-heads", + "data": "0x000318170b06000254050007000254040007000354030006000354040005000454040002000654050001000654060002000554060002000754040002000854030004000854010002000b540200075401000254010003000554050002000354080002000254090003000254080001000354090003540a0002540b00010001540b00" + }, + { + "filename": "125-head-25-shiga-heads", + "data": "0x000316160807000254050007000354040006000554030003000154010007540200030003540100015401000354020003000354030004540100010004540500035401000654040003540100010005540300035402000100045403000454020001000354020007540100010003540300075402000154020009540100025401000a540100025401000954010001000c54010002000a540200020009540300040003540700050002540700" + }, + { + "filename": "126-head-26-kyoto-heads", + "data": "0x0005171507030003540a000154010004540a0005540b0006540100025407000300045401000154070003000654070001000a54050002000b54030003000154010008540300050008540300080005540300080005540300070007540200090001540100035402000b00045401000c0004540c00025401000154" + }, + { + "filename": "127-head-27-osaka-heads", + "data": "0x000616150b05000254010001540200060004540100060005540600055406000554060005540500065405000554010006000454010006000354020005000554010005000654020001540100075403000754010001000554050003540800" + }, + { + "filename": "128-head-28-hyogo-heads", + "data": "0x0004181d07040005540800020007540800030007540100015405000300095405000300095405000400065407000400065407000400085401000154030002000c54030003000e5402000f5401000f5401001054010011541154010010540100025405000754010001540a000454030011000a0001540600090001540700080002540700070003540700060005540600070003540700070001540900" + }, + { + "filename": "129-head-29-nara-heads", + "data": "0x000316140b02000154080002000254010002540100015402000200075402000100075403000100075403000200085401000200095401000854020001000854020002000754020003000654020001000854020001000854020008540300095402000100065404000100055405000100015401000154010001540500" + }, + { + "filename": "130-head-30-wakayama-heads", + "data": "0x0004161606080002540600015402000754060001000a5405000200085406000100085407000100085407000200065408000100085407000a54060009540700020007540100015401000154030003000a54030005000954020006000954010005000b54060009540100070009540900055402000c0001540300" + }, + { + "filename": "131-head-31-tottori-heads", + "data": "0x00091c13061200025402000100015404000254040002540200045402000200015401001054020003001254010002001354010002000554010004540200085402000554030001540400075406540a00035401000254010005540a00015405000454120002541400" + }, + { + "filename": "132-head-32-shimane-heads", + "data": "0x000319190710000254100002540e000154030012001200120012000e00035401000b00055402000a00075401000b0006540100090008540100080007540300070008540300050007540600040006540800030008540700020004540c0005540d00010004540d0004540e00010003540e00010002540f00" + }, + { + "filename": "133-head-33-okayama-heads", + "data": "0x00031b1606050002540400025408000500045401000554060004000c540400015404000c540100035401000200125401000100125402001354020001001154030012540300125403001254030001001154030001001254020001001054040001001154030002000f54040002000a5402000254050003000b5407000300035402000554080004000154040001540b00" + }, + { + "filename": "134-head-34-hiroshima-heads", + "data": "0x00041c19020f000254010001540100035403000f00095402000e000a5402000d000b5402000c000c5402000d000b54020004000154010001540100015401000f540100020017540100030015540200020017540100020017540100010019541a54010019540100155401000354010005540100025401000954010002540200015401000200035404000a540200015401000154020002000254010001540300055405000354040003000154060002540300025409000a000154010002540c00090001541000080002541000" + }, + { + "filename": "135-head-35-yamaguchi-heads", + "data": "0x00051e17030d0001540d000c0002540d000b0003540d00090004540e000a0004540600015406000100035401000254020007540300025406000300015401000154010008540500015406000f540200015401000254060001001554050017540400010017540300010017540300175404000e54020008540300010002540100045401000154010001540300015401000654040001000154030002540b00045401000254010001540154130002540100015401000154010015000154050014000154020001540300" + }, + { + "filename": "136-head-36-tokushima-heads", + "data": "0x00031b15031500015402001200035403001100055402000b0005540100055402000400035402000c54030003001254030002001254040001001554020001001654010001001654010016540200020016540500025402000d54020009000b54040009000a5405000c00065406000c00045408000b00055408000c0003540900" + }, + { + "filename": "137-head-37-kagawa-heads", + "data": "0x00041c15041200045402001000055403000d0001540200055403001200015401000154030018000400015404000254010001540100025408000800085401000154060007000c54050005000e5405000154010001540100115403000100165401000200165402000f540500025402000d54090002000554030002540c00020003541300010003541400020001541500" + }, + { + "filename": "138-head-38-ehime-heads", + "data": "0x00021b1a020f00015409000f00015409001000015408000e0001540a000d00035409000900015402000454080001540c00055402000354010002540b000e540a000f540a00095406000a000754080009000854080007000954090006000a54090005000b5409000300025401000a54090001000254030006540d000154040008540c00070007540b00080004540d00060005540e0007000254010001540e00060004540f0005000154010003540f0007000154010001540f00" + }, + { + "filename": "139-head-39-kochi-heads", + "data": "0x00041a15030d0002540400015403000900085401000254030008000c54030007000e54020007000e54020006000854020007540300095406000454010004000754080003540100050005540a0002540100040006540b000154010001000154010006540e00020006540f00020006540f0002000454110003000454100002000454110001000154010001540100015411000154050001541000" + }, + { + "filename": "140-head-40-fukuoka-heads", + "data": "0x00021b18051200015403000b00045402000154040009000954040007000a54050008000a54040008000a5404000500015401000c5403000300015402000d5403000200035402000f54010014540100020014541154050004000c5406000600015402000754060009000654070008000854060007000954060006000954070005000b5406000500075401000354060006000454040002540600070002540d00070002540d00" + }, + { + "filename": "141-head-41-saga-heads", + "data": "0x00031c19040300015414000200045412000200045412000300045406000354080001000154020003540100095407000200115403000254040010540100035403001554030015540100015401001354020002540100135402001454040001001254050001001254050002000d5401000254060004000a5403000154060006000554010001540b00050007540c00060006540c00070006540b00080006540a00090005540a000c0002540a00" + }, + { + "filename": "142-head-42-nagasaki-heads", + "data": "0x00011a1908080001540900070002540900070002540900070001540a00070001540a00060001540b00060001540b00120012000b00015406000b0001540600120012000900015408001200080004540600050001540200015401000254060008000154020002540500050001540400015401000254040004000354040001540100025403000400025404000254020002540200030001540100015405000754010002540a000154020002540100035408000254010002540100015401000154080001540600" + }, + { + "filename": "143-head-43-kumamoto-heads", + "data": "0x00031816040e00035403000a0002540300035402000800065401000354020007000c54010007000c54010008000b54010009000b5409000a5401000a000854020007000a540300060001540300075403000154010001540600075404000100025402000354010006540500035401000354020006540500035403000154010009540300010002540100015402000a5403000254050009540400010001540100015402000b54030003000154020003540100065404000a0004540600" + }, + { + "filename": "144-head-44-oita-heads", + "data": "0x00041915040b0003540700060002540200055406000600095406000200025401000a54060001000c5401000154060001000a540100015408000b540a0001000a54020001540100035403001154040010540100015403000100025402000c5404000100035402000e5401000200025402000c54030007000c540100015407000d54010007000c54020008000254010004540200035401000b000254040001540300" + }, + { + "filename": "145-head-45-miyazaki-heads", + "data": "0x0004161708070001540100015402000254060008540500085401000500075402000400095401000400085402000500075402000400075403000500065403000400075403000a540400010009540400020008540400030007540400030008540300050005540400050005540400070002540500060003540500080001540500" + }, + { + "filename": "146-head-46-kagoshima-heads", + "data": "0x0003181f03070001540100015402000254070007000754070006000a54050007000954050007000a5404000200015403000b54040007000b54030001000154060005540200045402000154080003540300065409000354010008540900025403000754080003540400055401000600065403000454020007000554040004540100070006540300045401000c0001540200045402000f00035403000e0002540500150015001500030001540f0001540100130001540100120002540100120002540100120001540200060002540300015405000254020009000154010002540400025402000a0004540700" + }, + { + "filename": "147-head-47-okinawa-heads", + "data": "0x00011c15050f00015407000e000154070001541700170017001300015403001300025402001200035402000b0001540500045402000d00025402000354030001540c00075403000e00045405000d00035407000b00045408000a0002540b000a0003540a000b0003540900090003540b0003000154040003540c00090003540b00090002540c00" + } + ] + } +} \ No newline at end of file diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index 1b36d74a..9d76f1c7 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -3,7 +3,7 @@ import { ethers, network, SignerWithAddress, Contract } from "hardhat"; import { addresses } from '../../src/utils/addresses'; import { ethers } from 'ethers'; -let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, admin: SignerWithAddress; +let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, admin: SignerWithAddress; let token: Contract, minter: Contract, provider: Contract; const nounsDescriptorAddress = addresses.nounsDescriptor[network.name]; @@ -21,7 +21,7 @@ before(async () => { # npx hardhat run scripts/populate_localNouns.ts */ - [owner, user1, user2, admin] = await ethers.getSigners(); + [owner, user1, user2, user3, admin] = await ethers.getSigners(); const factoryProvider = await ethers.getContractFactory('LocalNounsProvider'); provider = await factoryProvider.deploy( @@ -45,17 +45,32 @@ before(async () => { describe('mint functions', function () { let result, tx; + it('mint from non-minter', async function () { await expect(token.connect(user1).functions.mint()) .revertedWith('Cannot use this function'); - await expect(token.connect(user1).functions.mintSelectedPrefecture(user1.address, 1)) + await expect(token.connect(user1).functions.mintSelectedPrefecture(user1.address, 1, 1)) .revertedWith('Sender is not the minter'); }); + it('mint at lock phaze', async function () { + + const [phaze] = await minter.functions.phase(); + expect(phaze).to.equal(0); // Lock + + await expect(minter.connect(user1).functions.mintSelectedPrefecture(1, 1)) + .revertedWith('Sale is locked'); + + await minter.connect(owner).functions.setPhase(2); + const [phaze2] = await minter.functions.phase(); + expect(phaze2).to.equal(2); // PublicSale + + }); + it('mint from minter', async function () { - await minter.connect(user1).functions.mintSelectedPrefecture(1); + await minter.connect(user1).functions.mintSelectedPrefecture(1,1); const [balance] = await token.functions.balanceOf(user1.address); expect(balance.toNumber()).to.equal(1); // user1は1つ保持 @@ -67,53 +82,77 @@ describe('mint functions', function () { expect(totalSupply.toNumber()).to.equal(1); // tokenId=1 }); - it('batch mint', async function () { - - //Aomori,Iwate(バージョン指定),ランダム,ランダム(バージョン指定)を、2個,3個ずつ、user2にmint - await minter.connect(user2).functions.mintSelectedPrefectureBatch([2, 103, 0, 100], [1, 1, 2, 2]); - - // user2に合計6個ミントされる - const [balance] = await token.functions.balanceOf(user2.address); - expect(balance.toNumber()).to.equal(1 + 2 + 3); - - const [owner1] = await token.functions.ownerOf(1); - const [owner2] = await token.functions.ownerOf(2); - const [owner3] = await token.functions.ownerOf(3); - const [owner4] = await token.functions.ownerOf(4); - const [owner5] = await token.functions.ownerOf(5); - const [owner6] = await token.functions.ownerOf(6); - - expect(owner1).to.equal(user2.address); - expect(owner2).to.equal(user2.address); - expect(owner3).to.equal(user2.address); - expect(owner4).to.equal(user2.address); - expect(owner5).to.equal(user2.address); - expect(owner6).to.equal(user2.address); - - // Traitsに指定した都道府県名が設定される - const [traits1] = await provider.functions.generateTraits(1); - const [traits2] = await provider.functions.generateTraits(2); - const [traits3] = await provider.functions.generateTraits(3); - const [traits4] = await provider.functions.generateTraits(4); - const [traits5] = await provider.functions.generateTraits(5); - const [traits6] = await provider.functions.generateTraits(6); - // head,accessoryがランダムなので除外 - // expect(traits1).to.equal('{"trait_type": "prefecture" , "value":"Aomori"}'); - // expect(traits2).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); - // expect(traits3).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); - // expect(traits4).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // expect(traits5).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // expect(traits6).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // console.log(traits1); - // console.log(traits2); - // console.log(traits3); - // console.log(traits4); - // console.log(traits5); - // console.log(traits6); + it('multiple mint', async function () { + + const [balance0] = await token.functions.balanceOf(user3.address); + await minter.connect(user3).functions.mintSelectedPrefecture(1,3); + + const [balance] = await token.functions.balanceOf(user3.address); + + expect(balance.toNumber()).to.equal(3); // user3は3つ追加 + + const [owner0] = await token.functions.ownerOf(1); + expect(owner0).to.equal(user3.address); + + const [owner1] = await token.functions.ownerOf(2); + expect(owner1).to.equal(user3.address); + + const [owner2] = await token.functions.ownerOf(3); + expect(owner2).to.equal(user3.address); const [totalSupply] = await token.functions.totalSupply(); - expect(totalSupply.toNumber()).to.equal(7); + expect(totalSupply.toNumber()).to.equal(4); // tokenId=1 }); + + // バッチミントは削除 + // it('batch mint', async function () { + + // //Aomori,Iwate(バージョン指定),ランダム,ランダム(バージョン指定)を、2個,3個ずつ、user2にmint + // // await minter.connect(user2).functions.mintSelectedPrefectureBatch([2, 103, 0, 100], [1, 1, 2, 2]); + // await minter.connect(user2).functions.mintSelectedPrefectureBatch([2, 3, 0, 0], [1, 1, 2, 2]); // バージョン未登録なのでバージョン指定なし + + // // user2に合計6個ミントされる + // const [balance] = await token.functions.balanceOf(user2.address); + // expect(balance.toNumber()).to.equal(1 + 2 + 3); + + // const [owner1] = await token.functions.ownerOf(1); + // const [owner2] = await token.functions.ownerOf(2); + // const [owner3] = await token.functions.ownerOf(3); + // const [owner4] = await token.functions.ownerOf(4); + // const [owner5] = await token.functions.ownerOf(5); + // const [owner6] = await token.functions.ownerOf(6); + + // expect(owner1).to.equal(user2.address); + // expect(owner2).to.equal(user2.address); + // expect(owner3).to.equal(user2.address); + // expect(owner4).to.equal(user2.address); + // expect(owner5).to.equal(user2.address); + // expect(owner6).to.equal(user2.address); + + // // Traitsに指定した都道府県名が設定される + // const [traits1] = await provider.functions.generateTraits(1); + // const [traits2] = await provider.functions.generateTraits(2); + // const [traits3] = await provider.functions.generateTraits(3); + // const [traits4] = await provider.functions.generateTraits(4); + // const [traits5] = await provider.functions.generateTraits(5); + // const [traits6] = await provider.functions.generateTraits(6); + // // head,accessoryがランダムなので除外 + // // expect(traits1).to.equal('{"trait_type": "prefecture" , "value":"Aomori"}'); + // // expect(traits2).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); + // // expect(traits3).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); + // // expect(traits4).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); + // // expect(traits5).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); + // // expect(traits6).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); + // // console.log(traits1); + // // console.log(traits2); + // // console.log(traits3); + // // console.log(traits4); + // // console.log(traits5); + // // console.log(traits6); + + // const [totalSupply] = await token.functions.totalSupply(); + // expect(totalSupply.toNumber()).to.equal(7); + // }); }); describe('P2P', function () { @@ -122,7 +161,7 @@ describe('P2P', function () { const price = ethers.BigNumber.from('1000000000000000'); it('not on sale', async function () { - await minter.connect(user1).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; @@ -168,12 +207,12 @@ describe('P2PTradable', function () { it('mint for test', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefectureBatch([5], [1]); + await minter.connect(user1).functions.mintSelectedPrefecture(5, 1); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; @@ -232,12 +271,12 @@ describe('P2PTradable', function () { it('put trade(都道府県指定なし)', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; @@ -264,12 +303,12 @@ describe('P2PTradable', function () { it('cancel trade', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefectureBatch([10], [1]); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; diff --git a/src/utils/addresses/localNounsDescriptor_localhost.ts b/src/utils/addresses/localNounsDescriptor_localhost.ts index e434919b..2475711b 100644 --- a/src/utils/addresses/localNounsDescriptor_localhost.ts +++ b/src/utils/addresses/localNounsDescriptor_localhost.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsDescriptor:"0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", + localNounsDescriptor:"0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD", } diff --git a/src/utils/addresses/localNounsDescriptor_mumbai.ts b/src/utils/addresses/localNounsDescriptor_mumbai.ts index 1091d558..5d3751e9 100644 --- a/src/utils/addresses/localNounsDescriptor_mumbai.ts +++ b/src/utils/addresses/localNounsDescriptor_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsDescriptor:"0xc0ce1B8DCd1045Ded1aBc983eb0577C91Dc67e0f", + localNounsDescriptor:"0x7351860b203bDDAC7e987F7d3B4e809960d05cf1", } diff --git a/src/utils/addresses/localNounsMinter_localhost.ts b/src/utils/addresses/localNounsMinter_localhost.ts index 327519a1..c08e5584 100644 --- a/src/utils/addresses/localNounsMinter_localhost.ts +++ b/src/utils/addresses/localNounsMinter_localhost.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsMinter:"0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", + localNounsMinter:"0x8198f5d8F8CfFE8f9C413d98a0A55aEB8ab9FbB7", } diff --git a/src/utils/addresses/localNounsMinter_mumbai.ts b/src/utils/addresses/localNounsMinter_mumbai.ts index 0ff65870..b9956f0b 100644 --- a/src/utils/addresses/localNounsMinter_mumbai.ts +++ b/src/utils/addresses/localNounsMinter_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsMinter:"0x461F5E3658380593E9a08D84c9074a8C9FE1fe1F", + localNounsMinter:"0x0d602965065c64e6d5d69834C246863472aac4A5", } diff --git a/src/utils/addresses/localNounsProvider_localhost.ts b/src/utils/addresses/localNounsProvider_localhost.ts index f732037f..ff3d0c5d 100644 --- a/src/utils/addresses/localNounsProvider_localhost.ts +++ b/src/utils/addresses/localNounsProvider_localhost.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsProvider:"0x0165878A594ca255338adfa4d48449f69242Eb8F", + localNounsProvider:"0x51A1ceB83B83F1985a81C295d1fF28Afef186E02", } diff --git a/src/utils/addresses/localNounsProvider_mumbai.ts b/src/utils/addresses/localNounsProvider_mumbai.ts index a54f793c..36843f0d 100644 --- a/src/utils/addresses/localNounsProvider_mumbai.ts +++ b/src/utils/addresses/localNounsProvider_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsProvider:"0x8d65Dd27E7910C18E6B83976753e912137f97454", + localNounsProvider:"0xfB4Fa72bcA36e02E24D2081EcBcf8D6d071CCE03", } diff --git a/src/utils/addresses/localNounsToken_localhost.ts b/src/utils/addresses/localNounsToken_localhost.ts index 4e2cbbb0..09135c78 100644 --- a/src/utils/addresses/localNounsToken_localhost.ts +++ b/src/utils/addresses/localNounsToken_localhost.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsToken:"0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + localNounsToken:"0x36b58F5C1969B7b6591D752ea6F5486D069010AB", } diff --git a/src/utils/addresses/localNounsToken_mumbai.ts b/src/utils/addresses/localNounsToken_mumbai.ts index 78b569d3..c8683abf 100644 --- a/src/utils/addresses/localNounsToken_mumbai.ts +++ b/src/utils/addresses/localNounsToken_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - localNounsToken:"0xbf1028b9CE3A40b1C13329dcb8a17ab9B96ffdA5", + localNounsToken:"0x4d21F695453D2d206D72A08086f0440A97A82125", } diff --git a/src/utils/addresses/localseeder_localhost.ts b/src/utils/addresses/localseeder_localhost.ts index a901ddde..83de0f6d 100644 --- a/src/utils/addresses/localseeder_localhost.ts +++ b/src/utils/addresses/localseeder_localhost.ts @@ -1,3 +1,3 @@ export const addresses = { - localseeder:"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + localseeder:"0xD8a5a9b31c3C0232E196d518E89Fd8bF83AcAd43", } diff --git a/src/utils/addresses/localseeder_mumbai.ts b/src/utils/addresses/localseeder_mumbai.ts index ce9db790..bad495e6 100644 --- a/src/utils/addresses/localseeder_mumbai.ts +++ b/src/utils/addresses/localseeder_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - localseeder:"0x87ca24C18dC424Bc3018F4955aca1AC123d52A97", + localseeder:"0x14E6BC05997989d6B5a1F2910Fe9eD4eC25F1294", } diff --git a/src/utils/addresses/nftDescriptor_localhost.ts b/src/utils/addresses/nftDescriptor_localhost.ts new file mode 100644 index 00000000..b9e2a303 --- /dev/null +++ b/src/utils/addresses/nftDescriptor_localhost.ts @@ -0,0 +1,3 @@ +export const addresses = { + nftDescriptor:"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", +} diff --git a/src/utils/addresses/nftDescriptor_mumbai.ts b/src/utils/addresses/nftDescriptor_mumbai.ts index 0631487f..26646f74 100644 --- a/src/utils/addresses/nftDescriptor_mumbai.ts +++ b/src/utils/addresses/nftDescriptor_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - nftDescriptor: "0xC93218fF7C44cbEB57c7661DCa886deCBc0E07C0", + nftDescriptor:"0x77dD7d8d4a7091a64c25Eb0127839ff1f467edCa", } diff --git a/src/utils/addresses/nounsDescriptor_localhost.ts b/src/utils/addresses/nounsDescriptor_localhost.ts new file mode 100644 index 00000000..2bfe8fe1 --- /dev/null +++ b/src/utils/addresses/nounsDescriptor_localhost.ts @@ -0,0 +1,3 @@ +export const addresses = { + nounsDescriptor:"0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", +} diff --git a/src/utils/addresses/nounsDescriptor_mumbai.ts b/src/utils/addresses/nounsDescriptor_mumbai.ts index b62e697d..908194a9 100644 --- a/src/utils/addresses/nounsDescriptor_mumbai.ts +++ b/src/utils/addresses/nounsDescriptor_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - nounsDescriptor: "0xA6f003aa2E8b8EbAe9e3b7792719A08Ea8683107", + nounsDescriptor:"0xE61d3572FDc4Bd1A49fa8bc691E3A0650FF0DdfC", } diff --git a/src/utils/addresses/nounsSeeder_localhost.ts b/src/utils/addresses/nounsSeeder_localhost.ts new file mode 100644 index 00000000..55c0737e --- /dev/null +++ b/src/utils/addresses/nounsSeeder_localhost.ts @@ -0,0 +1,3 @@ +export const addresses = { + nounsSeeder:"0x5FbDB2315678afecb367f032d93F642f64180aa3", +} diff --git a/src/utils/addresses/nounsSeeder_mumbai.ts b/src/utils/addresses/nounsSeeder_mumbai.ts index aa8f7c21..8433cc5d 100644 --- a/src/utils/addresses/nounsSeeder_mumbai.ts +++ b/src/utils/addresses/nounsSeeder_mumbai.ts @@ -1,3 +1,3 @@ export const addresses = { - nounsSeeder: "0x5f5C984E0BAf150D5a74ae21f4777Fd1947DE8c9", + nounsSeeder:"0x86c95EC4fA955505E0B904CFCF232E93e17a1c75", } From cf464e1a46fc4e7e3941be36d5773817a096c3ac Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 08:25:22 +0900 Subject: [PATCH 03/17] =?UTF-8?q?mintSelectedPrefectureBatch=E3=81=AE?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index abc8b21a..5ad2f851 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -80,26 +80,6 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { return _nextTokenId() - 1; } - function mintSelectedPrefectureBatch( - address _to, - uint256[] memory _prefectureId, - uint256[] memory _amount - ) public virtual returns (uint256 tokenId) { - require(msg.sender == minter, 'Sender is not the minter'); - require(_prefectureId.length == _amount.length, 'parametars length are different'); - require(_prefectureId.length > 0, 'parametars length is zero'); - - uint256 counter = 0; - for (uint256 i = 0; i < _prefectureId.length; i++) { - for (uint256 j = 0; j < _amount[i]; j++) { - assetProvider2.mint(_prefectureId[i], _nextTokenId() + counter++); - } - } - - _safeMint(_to, counter); - - return _nextTokenId() - 1; - } function mint() public payable override returns (uint256 tokenId) { revert('Cannot use this function'); From c528f8a605792e1f9859820099b984a730af5c26 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 09:17:04 +0900 Subject: [PATCH 04/17] =?UTF-8?q?mintSelectedPrefectureBatch=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contracts/localNouns/interfaces/ILocalNounsToken.sol | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol index c9330d17..12964e93 100644 --- a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol +++ b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol @@ -20,12 +20,6 @@ pragma solidity ^0.8.6; interface ILocalNounsToken { function mintSelectedPrefecture(address to, uint256 prefectureId, uint256 _amount) external returns (uint256 tokenId); - function mintSelectedPrefectureBatch( - address _to, - uint256[] memory _prefectureId, - uint256[] memory _amount - ) external returns (uint256 tokenId); - function setMinter(address _minter) external; // Fires when the owner puts the trade From 5206f5a5defaa8e374b7044e953a8109fe3e1ba0 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 09:21:53 +0900 Subject: [PATCH 05/17] =?UTF-8?q?tokenGate=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/localNouns/LocalNounsMinter.sol | 11 +++++++++-- contract/test/localNouns.ts | 9 +++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contract/contracts/localNouns/LocalNounsMinter.sol b/contract/contracts/localNouns/LocalNounsMinter.sol index e7a473bf..026924af 100644 --- a/contract/contracts/localNouns/LocalNounsMinter.sol +++ b/contract/contracts/localNouns/LocalNounsMinter.sol @@ -19,9 +19,11 @@ pragma solidity ^0.8.6; import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol'; import './interfaces/ILocalNounsToken.sol'; +import '../interfaces/ITokenGate.sol'; contract LocalNounsMinter is Ownable { ILocalNounsToken public token; + ITokenGate public immutable tokenGate; uint256 public mintPriceForSpecified = 0.03 ether; uint256 public mintPriceForNotSpecified = 0.01 ether; @@ -40,9 +42,10 @@ contract LocalNounsMinter is Ownable { address public administratorsAddress; // 運営ウォレット - constructor(ILocalNounsToken _token) { + constructor(ILocalNounsToken _token, ITokenGate _tokenGate) { token = _token; administratorsAddress = msg.sender; + tokenGate = _tokenGate; } function setLocalNounsToken(ILocalNounsToken _token) external onlyOwner { @@ -66,7 +69,11 @@ contract LocalNounsMinter is Ownable { } function mintSelectedPrefecture(uint256 _prefectureId, uint256 _amount) public payable returns (uint256 tokenId) { - require(phase != SalePhase.Locked, 'Sale is locked'); + if (phase == SalePhase.Locked) { + revert('Sale is locked'); + } else if (phase == SalePhase.PreSale) { + require(tokenGate.balanceOf(msg.sender) > 0); + } return token.mintSelectedPrefecture(msg.sender, _prefectureId, _amount); } diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index 9d76f1c7..da745bb6 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -4,7 +4,7 @@ import { addresses } from '../../src/utils/addresses'; import { ethers } from 'ethers'; let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, admin: SignerWithAddress; -let token: Contract, minter: Contract, provider: Contract; +let token: Contract, minter: Contract, provider: Contract, tokenGate: Contract; const nounsDescriptorAddress = addresses.nounsDescriptor[network.name]; const localNounsDescriptorAddress = addresses.localNounsDescriptor[network.name]; @@ -23,6 +23,11 @@ before(async () => { [owner, user1, user2, user3, admin] = await ethers.getSigners(); + const factoryTokenGate = await ethers.getContractFactory('AssetTokenGate'); + tokenGate = await factoryTokenGate.deploy(); + await tokenGate.deployed(); + // console.log(`##LocalNounsProvider="${provider.address}"`); + const factoryProvider = await ethers.getContractFactory('LocalNounsProvider'); provider = await factoryProvider.deploy( nounsDescriptorAddress, localNounsDescriptorAddress, nounsSeederAddress, localSeederAddress); @@ -35,7 +40,7 @@ before(async () => { // console.log(`##LocalNounsToken="${token.address}"`); const factoryMinter = await ethers.getContractFactory('LocalNounsMinter'); - minter = await factoryMinter.deploy(token.address); + minter = await factoryMinter.deploy(token.address, tokenGate.address); await minter.deployed(); // console.log(`##LocalNounsMinter="${minter.address}"`); From cf9776d4b13bdb59943a4fe1ced5d15ec251c9bf Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 10:45:21 +0900 Subject: [PATCH 06/17] =?UTF-8?q?whitelist=E3=82=92public=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/libs/AssetTokenGate.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/contracts/libs/AssetTokenGate.sol b/contract/contracts/libs/AssetTokenGate.sol index a4a4fd1b..dd74f803 100644 --- a/contract/contracts/libs/AssetTokenGate.sol +++ b/contract/contracts/libs/AssetTokenGate.sol @@ -11,7 +11,7 @@ import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import '../interfaces/ITokenGate.sol'; contract AssetTokenGate is Ownable, ITokenGate { - IERC721[] whitelist; + IERC721[] public whitelist; function setWhitelist(IERC721[] memory _whitelist) external onlyOwner { whitelist = _whitelist; From ec80ef1b872b6a5a8bfb8199b982df0877c93b46 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 10:46:32 +0900 Subject: [PATCH 07/17] =?UTF-8?q?tokenGate=E3=81=AB=E3=82=88=E3=82=8B?= =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contracts/localNouns/LocalNounsMinter.sol | 5 ++- contract/test/localNouns.ts | 44 ++++++++++++++++--- src/utils/addresses.ts | 3 ++ src/utils/addresses/sample_localhost.ts | 7 ++- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/contract/contracts/localNouns/LocalNounsMinter.sol b/contract/contracts/localNouns/LocalNounsMinter.sol index 026924af..d5225813 100644 --- a/contract/contracts/localNouns/LocalNounsMinter.sol +++ b/contract/contracts/localNouns/LocalNounsMinter.sol @@ -28,7 +28,7 @@ contract LocalNounsMinter is Ownable { uint256 public mintPriceForSpecified = 0.03 ether; uint256 public mintPriceForNotSpecified = 0.01 ether; - uint256 public constant mintMax = 1200; + uint256 public constant mintMax = 1500; mapping(address => uint256) public preferentialPurchacedCount; @@ -72,8 +72,9 @@ contract LocalNounsMinter is Ownable { if (phase == SalePhase.Locked) { revert('Sale is locked'); } else if (phase == SalePhase.PreSale) { - require(tokenGate.balanceOf(msg.sender) > 0); + require(tokenGate.balanceOf(msg.sender) > 0, 'TokenGate token is needed'); } + return token.mintSelectedPrefecture(msg.sender, _prefectureId, _amount); } diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index da745bb6..28b3cd73 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -2,14 +2,16 @@ import { expect } from 'chai'; import { ethers, network, SignerWithAddress, Contract } from "hardhat"; import { addresses } from '../../src/utils/addresses'; import { ethers } from 'ethers'; +import { abi as sampleTokenAbi } from "../artifacts/contracts/sampleToken.sol/sampleToken"; -let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, admin: SignerWithAddress; -let token: Contract, minter: Contract, provider: Contract, tokenGate: Contract; +let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress, admin: SignerWithAddress; +let token: Contract, minter: Contract, provider: Contract, tokenGate: Contract, sampleToken: Contract; const nounsDescriptorAddress = addresses.nounsDescriptor[network.name]; const localNounsDescriptorAddress = addresses.localNounsDescriptor[network.name]; const nounsSeederAddress = addresses.nounsSeeder[network.name]; const localSeederAddress = addresses.localSeeder[network.name]; +const sampleTokenAddress = addresses.sampleToken[network.name]; before(async () => { /* `npx hardhat node`実行後、このスクリプトを実行する前に、Nouns,LocalNounsの関連するコントラクトを @@ -19,14 +21,14 @@ before(async () => { # npx hardhat run scripts/populate_nounsV1.ts # npx hardhat run scripts/deploy_localNouns.ts # npx hardhat run scripts/populate_localNouns.ts + # npx hardhat run scripts/deploy_sample.ts */ - [owner, user1, user2, user3, admin] = await ethers.getSigners(); + [owner, user1, user2, user3, user4, admin] = await ethers.getSigners(); const factoryTokenGate = await ethers.getContractFactory('AssetTokenGate'); tokenGate = await factoryTokenGate.deploy(); await tokenGate.deployed(); - // console.log(`##LocalNounsProvider="${provider.address}"`); const factoryProvider = await ethers.getContractFactory('LocalNounsProvider'); provider = await factoryProvider.deploy( @@ -46,6 +48,12 @@ before(async () => { await token.setMinter(minter.address); + // sampleTokenのコントラクト定義 + sampleToken = await ethers.getContractAt(sampleTokenAbi, sampleTokenAddress); + + // tokenGateにsampleTokenをセット + await tokenGate.setWhitelist([sampleToken.address]); + }); describe('mint functions', function () { @@ -75,7 +83,7 @@ describe('mint functions', function () { }); it('mint from minter', async function () { - await minter.connect(user1).functions.mintSelectedPrefecture(1,1); + await minter.connect(user1).functions.mintSelectedPrefecture(1, 1); const [balance] = await token.functions.balanceOf(user1.address); expect(balance.toNumber()).to.equal(1); // user1は1つ保持 @@ -90,7 +98,7 @@ describe('mint functions', function () { it('multiple mint', async function () { const [balance0] = await token.functions.balanceOf(user3.address); - await minter.connect(user3).functions.mintSelectedPrefecture(1,3); + await minter.connect(user3).functions.mintSelectedPrefecture(1, 3); const [balance] = await token.functions.balanceOf(user3.address); @@ -109,6 +117,30 @@ describe('mint functions', function () { expect(totalSupply.toNumber()).to.equal(4); // tokenId=1 }); + it('tokenGate', async function () { + + await minter.connect(owner).functions.setPhase(1); + const [phaze] = await minter.functions.phase(); + expect(phaze).to.equal(1); // PreSale + + await expect(minter.connect(user4).functions.mintSelectedPrefecture(1, 1)) + .revertedWith('TokenGate token is needed'); + + // sampleTokenをミント + await sampleToken.connect(user4).functions.mint(); + + await minter.connect(user4).functions.mintSelectedPrefecture(1, 3); + + const [balance] = await token.functions.balanceOf(user4.address); + + expect(balance.toNumber()).to.equal(3); // user3は3つ追加 + + await minter.connect(owner).functions.setPhase(2); + const [phaze2] = await minter.functions.phase(); + expect(phaze2).to.equal(2); // PublicSale + + }); + // バッチミントは削除 // it('batch mint', async function () { diff --git a/src/utils/addresses.ts b/src/utils/addresses.ts index 20119641..345e2521 100644 --- a/src/utils/addresses.ts +++ b/src/utils/addresses.ts @@ -183,6 +183,9 @@ export const addresses: Addresses = { goerli: sample_goerli.providerAddress, localhost: sample_localhost.providerAddress, }, + sampleToken: { + localhost: sample_localhost.sampleToken, + }, assetStore: { goerli: store_goerli.storeAddress, mainnet: store_mainnet.storeAddress, diff --git a/src/utils/addresses/sample_localhost.ts b/src/utils/addresses/sample_localhost.ts index 10429ab4..153d86ba 100644 --- a/src/utils/addresses/sample_localhost.ts +++ b/src/utils/addresses/sample_localhost.ts @@ -1,5 +1,4 @@ export const addresses = { - svgHelperAddress: "0xAD2935E147b61175D5dc3A9e7bDa93B0975A43BA", - providerAddress: "0x00CAC06Dd0BB4103f8b62D280fE9BCEE8f26fD59", - sampleToken: "0x4951A1C579039EbfCBA0BE33D2cd3A6D30b0f802", -}; + providerAddress:"0x7Cf4be31f546c04787886358b9486ca3d62B9acf", + sampleToken:"0x33E45b187da34826aBCEDA1039231Be46f1b05Af" +} From aa5acfa02cc7ae4b50a109c83852d9a85c149478 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Wed, 25 Oct 2023 23:30:28 +0900 Subject: [PATCH 08/17] =?UTF-8?q?tokenGate=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/scripts/deploy_localNouns.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contract/scripts/deploy_localNouns.ts b/contract/scripts/deploy_localNouns.ts index 6f3357b4..59ce8bad 100644 --- a/contract/scripts/deploy_localNouns.ts +++ b/contract/scripts/deploy_localNouns.ts @@ -12,6 +12,10 @@ async function main() { const [minter] = await ethers.getSigners(); console.log(`##minter="${minter.address}"`); + const factoryTokenGate = await ethers.getContractFactory('AssetTokenGate'); + const tokenGate = await factoryTokenGate.deploy(); + await tokenGate.deployed(); + const factorySeeder = await ethers.getContractFactory('LocalNounsSeeder'); const localseeder = await factorySeeder.deploy(); await localseeder.deployed(); @@ -57,7 +61,7 @@ async function main() { await writeFile(`../src/utils/addresses/localNounsToken_${network.name}.ts`, addresses4, () => { }); const factoryMinter = await ethers.getContractFactory('LocalNounsMinter'); - const minterContract = await factoryMinter.deploy(token.address); + const minterContract = await factoryMinter.deploy(token.address, tokenGate.address); await minterContract.deployed(); console.log(`##LocalNounsMinter="${minterContract.address}"`); await runCommand(`npx hardhat verify ${minterContract.address} ${token.address} --network ${network.name} &`); From 0ece521eb79dce48148e8776c5a3fae862db5fc0 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 07:36:52 +0900 Subject: [PATCH 09/17] =?UTF-8?q?*=5Flocalhost.ts=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 390fe766..54c23a40 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ pnpm-debug.log* *~ -contract/contracts/fonts/font.sol \ No newline at end of file +contract/contracts/fonts/font.sol +src/utils/addresses/*_localhost.ts \ No newline at end of file From 57c53b2cc6a8bdb682880a23c5e0e45df469181a Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 08:03:47 +0900 Subject: [PATCH 10/17] =?UTF-8?q?Send=20ETH=20=E3=83=81=E3=82=A7=E3=83=83?= =?UTF-8?q?=E3=82=AF=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contracts/localNouns/LocalNounsMinter.sol | 12 ++++- contract/test/localNouns.ts | 52 ++++++++++++++----- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/contract/contracts/localNouns/LocalNounsMinter.sol b/contract/contracts/localNouns/LocalNounsMinter.sol index d5225813..f84ae172 100644 --- a/contract/contracts/localNouns/LocalNounsMinter.sol +++ b/contract/contracts/localNouns/LocalNounsMinter.sol @@ -25,8 +25,8 @@ contract LocalNounsMinter is Ownable { ILocalNounsToken public token; ITokenGate public immutable tokenGate; - uint256 public mintPriceForSpecified = 0.03 ether; - uint256 public mintPriceForNotSpecified = 0.01 ether; + uint256 public mintPriceForSpecified = 0.003 ether; + uint256 public mintPriceForNotSpecified = 0.001 ether; uint256 public constant mintMax = 1500; @@ -74,6 +74,14 @@ contract LocalNounsMinter is Ownable { } else if (phase == SalePhase.PreSale) { require(tokenGate.balanceOf(msg.sender) > 0, 'TokenGate token is needed'); } + + uint256 mintPrice; + if(_prefectureId == 0){ + mintPrice = mintPriceForNotSpecified; + }else{ + mintPrice = mintPriceForSpecified; + } + require(msg.value >= mintPrice * _amount, 'Must send the mint price'); return token.mintSelectedPrefecture(msg.sender, _prefectureId, _amount); } diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index 28b3cd73..a19201dd 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -83,7 +83,9 @@ describe('mint functions', function () { }); it('mint from minter', async function () { - await minter.connect(user1).functions.mintSelectedPrefecture(1, 1); + + const txParams = { value: ethers.utils.parseUnits("0.001", "ether") }; + await minter.connect(user1).functions.mintSelectedPrefecture(0, 1,txParams); const [balance] = await token.functions.balanceOf(user1.address); expect(balance.toNumber()).to.equal(1); // user1は1つ保持 @@ -98,7 +100,9 @@ describe('mint functions', function () { it('multiple mint', async function () { const [balance0] = await token.functions.balanceOf(user3.address); - await minter.connect(user3).functions.mintSelectedPrefecture(1, 3); + + const txParams = { value: ethers.utils.parseUnits("0.009", "ether") }; + await minter.connect(user3).functions.mintSelectedPrefecture(1, 3, txParams); const [balance] = await token.functions.balanceOf(user3.address); @@ -123,17 +127,18 @@ describe('mint functions', function () { const [phaze] = await minter.functions.phase(); expect(phaze).to.equal(1); // PreSale - await expect(minter.connect(user4).functions.mintSelectedPrefecture(1, 1)) + const txParams = { value: ethers.utils.parseUnits("0.009", "ether") }; + await expect(minter.connect(user4).functions.mintSelectedPrefecture(1, 1, txParams)) .revertedWith('TokenGate token is needed'); // sampleTokenをミント await sampleToken.connect(user4).functions.mint(); - await minter.connect(user4).functions.mintSelectedPrefecture(1, 3); + await minter.connect(user4).functions.mintSelectedPrefecture(1, 3, txParams); const [balance] = await token.functions.balanceOf(user4.address); - expect(balance.toNumber()).to.equal(3); // user3は3つ追加 + expect(balance.toNumber()).to.equal(3); // user4は3つ追加 await minter.connect(owner).functions.setPhase(2); const [phaze2] = await minter.functions.phase(); @@ -141,6 +146,24 @@ describe('mint functions', function () { }); + it('Send eth', async function () { + + await minter.connect(owner).functions.setPhase(2); + const [phaze] = await minter.functions.phase(); + expect(phaze).to.equal(2); // PreSale + + // 都道府県指定 OKパターンは'multiple mint'テストで実施 + const txParams = { value: ethers.utils.parseUnits("0.0059", "ether") }; + await expect(minter.connect(user4).functions.mintSelectedPrefecture(1, 2, txParams)) + .revertedWith('Must send the mint price'); + + // 都道府県指定なし OKパターンは'mint from minter'テストで実施 + const txParams2 = { value: ethers.utils.parseUnits("0.0019", "ether") }; + await expect(minter.connect(user4).functions.mintSelectedPrefecture(0, 2, txParams2)) + .revertedWith('Must send the mint price'); + + }); + // バッチミントは削除 // it('batch mint', async function () { @@ -198,7 +221,9 @@ describe('P2P', function () { const price = ethers.BigNumber.from('1000000000000000'); it('not on sale', async function () { - await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); + + const txParams = { value: ethers.utils.parseUnits("0.003", "ether") }; + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; @@ -244,12 +269,13 @@ describe('P2PTradable', function () { it('mint for test', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefecture(5, 1); + const txParams = { value: ethers.utils.parseUnits("0.003", "ether") }; + await minter.connect(user1).functions.mintSelectedPrefecture(5, 1, txParams); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; @@ -308,12 +334,13 @@ describe('P2PTradable', function () { it('put trade(都道府県指定なし)', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); + const txParams = { value: ethers.utils.parseUnits("0.003", "ether") }; + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; @@ -340,12 +367,13 @@ describe('P2PTradable', function () { it('cancel trade', async function () { // for user1 - await minter.connect(user1).functions.mintSelectedPrefecture(10, 1); + const txParams = { value: ethers.utils.parseUnits("0.003", "ether") }; + await minter.connect(user1).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId1 = result.toNumber() - 1; // for user2 - await minter.connect(user2).functions.mintSelectedPrefecture(10, 1); + await minter.connect(user2).functions.mintSelectedPrefecture(10, 1, txParams); result = await token.totalSupply(); tokenId2 = result.toNumber() - 1; From 2b8df4181fb6f61d7d17acecc9b03e2537defaf4 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 08:49:52 +0900 Subject: [PATCH 11/17] =?UTF-8?q?=5FnextTokenId=E3=81=AF=5FsafeMint?= =?UTF-8?q?=E3=81=A7=E6=9B=B4=E6=96=B0=E3=81=95=E3=82=8C=E3=82=8B=E3=81=AE?= =?UTF-8?q?=E3=81=A7=20index=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index 5ad2f851..72ef81ef 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -74,13 +74,12 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { ) public virtual returns (uint256 tokenId) { require(msg.sender == minter, 'Sender is not the minter'); for (uint256 i = 0; i < _amount; i++) { - assetProvider2.mint(_prefectureId, _nextTokenId()); + assetProvider2.mint(_prefectureId, _nextTokenId() + i); } _safeMint(_to, _amount); return _nextTokenId() - 1; } - function mint() public payable override returns (uint256 tokenId) { revert('Cannot use this function'); } From 0416893c50c8049d0feeb6e1b9b1887390fbf8f1 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 08:51:17 +0900 Subject: [PATCH 12/17] =?UTF-8?q?=E9=83=BD=E9=81=93=E5=BA=9C=E7=9C=8C?= =?UTF-8?q?=E3=81=94=E3=81=A8=E3=81=AE=E3=83=9F=E3=83=B3=E3=83=88=E6=95=B0?= =?UTF-8?q?mintNumberPerPrefecture=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../localNouns/LocalNounsProvider.sol | 5 +- contract/test/localNouns.ts | 74 ++++++------------- 2 files changed, 26 insertions(+), 53 deletions(-) diff --git a/contract/contracts/localNouns/LocalNounsProvider.sol b/contract/contracts/localNouns/LocalNounsProvider.sol index 8fad8bff..c0f6e201 100644 --- a/contract/contracts/localNouns/LocalNounsProvider.sol +++ b/contract/contracts/localNouns/LocalNounsProvider.sol @@ -32,6 +32,7 @@ contract LocalNounsProvider is IAssetProviderExMint, IERC165, Ownable { mapping(uint256 => INounsSeeder.Seed) public seeds; mapping(uint256 => uint256) public tokenIdToPrefectureId; mapping(uint256 => string) public prefectureName; + mapping(uint256 => uint256) public mintNumberPerPrefecture; // 都道府県ごとのミント数 constructor( INounsDescriptor _descriptor, @@ -172,7 +173,9 @@ contract LocalNounsProvider is IAssetProviderExMint, IERC165, Ownable { } seeds[_assetId] = generateSeed(prefectureId, _assetId); - tokenIdToPrefectureId[_assetId] = prefectureId % 100; // 1,2桁目:都道府県番号、3桁目以降:バージョン番号 + uint256 prefectureId = prefectureId % 100; // 1,2桁目:都道府県番号、3桁目以降:バージョン番号 + tokenIdToPrefectureId[_assetId] = prefectureId; + mintNumberPerPrefecture[prefectureId]++; nextTokenId++; return _assetId; diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index a19201dd..2d345565 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -95,6 +95,10 @@ describe('mint functions', function () { const [totalSupply] = await token.functions.totalSupply(); expect(totalSupply.toNumber()).to.equal(1); // tokenId=1 + + const [traits1] = await provider.functions.generateTraits(0); + console.log('mint from minter',traits1); + }); it('multiple mint', async function () { @@ -102,7 +106,7 @@ describe('mint functions', function () { const [balance0] = await token.functions.balanceOf(user3.address); const txParams = { value: ethers.utils.parseUnits("0.009", "ether") }; - await minter.connect(user3).functions.mintSelectedPrefecture(1, 3, txParams); + await minter.connect(user3).functions.mintSelectedPrefecture(16, 3, txParams); const [balance] = await token.functions.balanceOf(user3.address); @@ -119,6 +123,23 @@ describe('mint functions', function () { const [totalSupply] = await token.functions.totalSupply(); expect(totalSupply.toNumber()).to.equal(4); // tokenId=1 + + // Traitsに指定した都道府県名が設定される + const [traits1] = await provider.functions.generateTraits(1); + const [traits2] = await provider.functions.generateTraits(2); + const [traits3] = await provider.functions.generateTraits(3); + // head,accessoryがランダムなので県のみチェック(head,accessoryは目視) + console.log('multiple mint',traits1); + console.log('multiple mint',traits2); + console.log('multiple mint',traits3); + expect(traits1.includes('{"trait_type": "prefecture" , "value":"Toyama"}')).to.equal(true); + expect(traits2.includes('{"trait_type": "prefecture" , "value":"Toyama"}')).to.equal(true); + expect(traits3.includes('{"trait_type": "prefecture" , "value":"Toyama"}')).to.equal(true); + + // 都道府県ごとのミント数 + const [mintNumberPerPrefecture] = await provider.functions.mintNumberPerPrefecture(16); + expect(mintNumberPerPrefecture.toNumber()).to.equal(3); // tokenId=1 + }); it('tokenGate', async function () { @@ -164,57 +185,6 @@ describe('mint functions', function () { }); - // バッチミントは削除 - // it('batch mint', async function () { - - // //Aomori,Iwate(バージョン指定),ランダム,ランダム(バージョン指定)を、2個,3個ずつ、user2にmint - // // await minter.connect(user2).functions.mintSelectedPrefectureBatch([2, 103, 0, 100], [1, 1, 2, 2]); - // await minter.connect(user2).functions.mintSelectedPrefectureBatch([2, 3, 0, 0], [1, 1, 2, 2]); // バージョン未登録なのでバージョン指定なし - - // // user2に合計6個ミントされる - // const [balance] = await token.functions.balanceOf(user2.address); - // expect(balance.toNumber()).to.equal(1 + 2 + 3); - - // const [owner1] = await token.functions.ownerOf(1); - // const [owner2] = await token.functions.ownerOf(2); - // const [owner3] = await token.functions.ownerOf(3); - // const [owner4] = await token.functions.ownerOf(4); - // const [owner5] = await token.functions.ownerOf(5); - // const [owner6] = await token.functions.ownerOf(6); - - // expect(owner1).to.equal(user2.address); - // expect(owner2).to.equal(user2.address); - // expect(owner3).to.equal(user2.address); - // expect(owner4).to.equal(user2.address); - // expect(owner5).to.equal(user2.address); - // expect(owner6).to.equal(user2.address); - - // // Traitsに指定した都道府県名が設定される - // const [traits1] = await provider.functions.generateTraits(1); - // const [traits2] = await provider.functions.generateTraits(2); - // const [traits3] = await provider.functions.generateTraits(3); - // const [traits4] = await provider.functions.generateTraits(4); - // const [traits5] = await provider.functions.generateTraits(5); - // const [traits6] = await provider.functions.generateTraits(6); - // // head,accessoryがランダムなので除外 - // // expect(traits1).to.equal('{"trait_type": "prefecture" , "value":"Aomori"}'); - // // expect(traits2).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); - // // expect(traits3).to.equal('{"trait_type": "prefecture" , "value":"Iwate"}'); - // // expect(traits4).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // // expect(traits5).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // // expect(traits6).to.equal('{"trait_type": "prefecture" , "value":"Miyagi"}'); - // // console.log(traits1); - // // console.log(traits2); - // // console.log(traits3); - // // console.log(traits4); - // // console.log(traits5); - // // console.log(traits6); - - // const [totalSupply] = await token.functions.totalSupply(); - // expect(totalSupply.toNumber()).to.equal(7); - // }); -}); - describe('P2P', function () { let tx, result, tokenId1: number; const zeroAddress = '0x0000000000000000000000000000000000000000'; From 7e69903a86fd8ded87f35e61027279fbea55b897 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 09:40:56 +0900 Subject: [PATCH 13/17] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/localNouns/LocalNounsProvider.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contract/contracts/localNouns/LocalNounsProvider.sol b/contract/contracts/localNouns/LocalNounsProvider.sol index c0f6e201..7e9f6470 100644 --- a/contract/contracts/localNouns/LocalNounsProvider.sol +++ b/contract/contracts/localNouns/LocalNounsProvider.sol @@ -173,7 +173,7 @@ contract LocalNounsProvider is IAssetProviderExMint, IERC165, Ownable { } seeds[_assetId] = generateSeed(prefectureId, _assetId); - uint256 prefectureId = prefectureId % 100; // 1,2桁目:都道府県番号、3桁目以降:バージョン番号 + uint256 prefectureId = prefectureId % 100; // 下2桁:都道府県番号、下3桁より上位:バージョン番号 tokenIdToPrefectureId[_assetId] = prefectureId; mintNumberPerPrefecture[prefectureId]++; nextTokenId++; From 55e49adec1bfcb4e73e41f754df0fb3ee3967cc8 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 09:52:51 +0900 Subject: [PATCH 14/17] =?UTF-8?q?=E9=83=BD=E9=81=93=E5=BA=9C=E7=9C=8C?= =?UTF-8?q?=E7=95=AA=E5=8F=B7=E3=81=AE=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 2 ++ contract/test/localNouns.ts | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index 72ef81ef..f8c79af0 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -73,6 +73,8 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { uint256 _amount ) public virtual returns (uint256 tokenId) { require(msg.sender == minter, 'Sender is not the minter'); + require(_prefectureId % 100 <= 47, 'Invalid prefectureId'); + for (uint256 i = 0; i < _amount; i++) { assetProvider2.mint(_prefectureId, _nextTokenId() + i); } diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index 2d345565..55323bba 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -82,6 +82,14 @@ describe('mint functions', function () { }); + it('Invalid prefectureId', async function () { + + // OKパターンは別テストで実施 + const txParams = { value: ethers.utils.parseUnits("0.003", "ether") }; + await expect(minter.connect(user4).functions.mintSelectedPrefecture(48, 1, txParams)) + .revertedWith('Invalid prefectureId'); + }); + it('mint from minter', async function () { const txParams = { value: ethers.utils.parseUnits("0.001", "ether") }; @@ -184,6 +192,7 @@ describe('mint functions', function () { .revertedWith('Must send the mint price'); }); +}); describe('P2P', function () { let tx, result, tokenId1: number; From 1f91eed3847c21ac636d3a1c83298cca1383be35 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 09:59:43 +0900 Subject: [PATCH 15/17] =?UTF-8?q?=E7=B6=99=E6=89=BF=E5=85=83=E3=81=AEmintP?= =?UTF-8?q?rice,=20mintLimit=E3=81=AF=E4=BD=BF=E7=94=A8=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index f8c79af0..2af59518 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -27,9 +27,8 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { ) ProviderTokenA2(_assetProvider, 'Local Nouns', 'Local Nouns') { description = 'Local Nouns Token.'; assetProvider2 = _assetProvider; - // mintPrice = 1e13; // 0.001 - mintPrice = 0; - mintLimit = 5000; + // mintPrice = 1e13; // 0.001 ※ mintPriceは Minterコントラクトで制御するため使用しない + // mintLimit = 5000; ※ mintLimitは Minterコントラクトで制御するため使用しない minter = _minter; administratorsAddress = msg.sender; } From 2331227b1a00261adcb6ca8ed8dc3b294c652591 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 10:05:36 +0900 Subject: [PATCH 16/17] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index 2af59518..ff4e8601 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -66,6 +66,12 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { ); } + /** + 都道府県番号を指定してミントします。 + 都道府県番号の下2桁=0を指定すると都道府県がランダムで選択されます。 + 都道府県番号の下3桁目以降はバージョン番号です。 + ミント価格、ミント上限数は、Minterコントラクト側で制御するため、継承元のmintPrice, mintLimitは使用しません。 + */ function mintSelectedPrefecture( address _to, uint256 _prefectureId, From bddb21b435057969a9be3e39ee8b7cf32c3afc78 Mon Sep 17 00:00:00 2001 From: eibakatsu Date: Thu, 26 Oct 2023 10:56:28 +0900 Subject: [PATCH 17/17] =?UTF-8?q?=E3=83=9F=E3=83=B3=E3=83=88=E6=95=B0?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E3=81=AE=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contract/contracts/LocalNounsToken.sol | 5 ++++ .../contracts/localNouns/LocalNounsMinter.sol | 10 +++++-- .../interfaces/ILocalNounsToken.sol | 3 ++ contract/test/localNouns.ts | 28 +++++++++++++++++-- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/contract/contracts/LocalNounsToken.sol b/contract/contracts/LocalNounsToken.sol index ff4e8601..655d3b44 100644 --- a/contract/contracts/LocalNounsToken.sol +++ b/contract/contracts/LocalNounsToken.sol @@ -171,4 +171,9 @@ contract LocalNounsToken is ProviderTokenA2, ILocalNounsToken { (bool sent, ) = payable(administratorsAddress).call{ value: address(this).balance }(''); require(sent, 'failed to move fund to administratorsAddress contract'); } + + // iLocalNounsTokenでERC721のtotalSupplyを使用したいけど、二重継承でエラーになるので個別関数を準備 + function totalSupply2() public view returns (uint256) { + return super.totalSupply(); + } } diff --git a/contract/contracts/localNouns/LocalNounsMinter.sol b/contract/contracts/localNouns/LocalNounsMinter.sol index f84ae172..9195dce6 100644 --- a/contract/contracts/localNouns/LocalNounsMinter.sol +++ b/contract/contracts/localNouns/LocalNounsMinter.sol @@ -28,7 +28,7 @@ contract LocalNounsMinter is Ownable { uint256 public mintPriceForSpecified = 0.003 ether; uint256 public mintPriceForNotSpecified = 0.001 ether; - uint256 public constant mintMax = 1500; + uint256 public mintMax = 1500; mapping(address => uint256) public preferentialPurchacedCount; @@ -48,6 +48,10 @@ contract LocalNounsMinter is Ownable { tokenGate = _tokenGate; } + function setMintMax(uint256 _mintMax) external onlyOwner { + mintMax = _mintMax; + } + function setLocalNounsToken(ILocalNounsToken _token) external onlyOwner { token = _token; } @@ -74,7 +78,9 @@ contract LocalNounsMinter is Ownable { } else if (phase == SalePhase.PreSale) { require(tokenGate.balanceOf(msg.sender) > 0, 'TokenGate token is needed'); } - + + require(token.totalSupply2() + _amount <= mintMax, 'Over the mint limit'); + uint256 mintPrice; if(_prefectureId == 0){ mintPrice = mintPriceForNotSpecified; diff --git a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol index 12964e93..f756793d 100644 --- a/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol +++ b/contract/contracts/localNouns/interfaces/ILocalNounsToken.sol @@ -22,6 +22,9 @@ interface ILocalNounsToken { function setMinter(address _minter) external; + // iLocalNounsTokenでERC721のtotalSupplyを使用したいけど、二重継承でエラーになるので個別関数を準備 + function totalSupply2() external returns (uint256); + // Fires when the owner puts the trade event PutTradePrefecture(uint256 indexed tokenId, uint256[] _prefectures); diff --git a/contract/test/localNouns.ts b/contract/test/localNouns.ts index 55323bba..98d5e631 100644 --- a/contract/test/localNouns.ts +++ b/contract/test/localNouns.ts @@ -4,7 +4,7 @@ import { addresses } from '../../src/utils/addresses'; import { ethers } from 'ethers'; import { abi as sampleTokenAbi } from "../artifacts/contracts/sampleToken.sol/sampleToken"; -let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress, admin: SignerWithAddress; +let owner: SignerWithAddress, user1: SignerWithAddress, user2: SignerWithAddress, user3: SignerWithAddress, user4: SignerWithAddress, user5: SignerWithAddress, admin: SignerWithAddress; let token: Contract, minter: Contract, provider: Contract, tokenGate: Contract, sampleToken: Contract; const nounsDescriptorAddress = addresses.nounsDescriptor[network.name]; @@ -24,7 +24,7 @@ before(async () => { # npx hardhat run scripts/deploy_sample.ts */ - [owner, user1, user2, user3, user4, admin] = await ethers.getSigners(); + [owner, user1, user2, user3, user4, user5, admin] = await ethers.getSigners(); const factoryTokenGate = await ethers.getContractFactory('AssetTokenGate'); tokenGate = await factoryTokenGate.deploy(); @@ -210,6 +210,30 @@ describe('P2P', function () { await expect(token.connect(user2).purchase(tokenId1, user2.address, zeroAddress)).revertedWith('Token is not on sale'); }); + it('Over the mint limit', async function () { + + // mintMaxに現在の発行数+1をセット + const [totalSupply] = await token.functions.totalSupply(); + await minter.functions.setMintMax(totalSupply.toNumber()+1); + const [mintMax] = await minter.functions.mintMax(); + expect(mintMax.toNumber()).to.equal(totalSupply.toNumber()+1); + + const txParams = { value: ethers.utils.parseUnits("0.006", "ether") }; + await expect(minter.connect(user5).functions.mintSelectedPrefecture(47, 2, txParams)) + .revertedWith('Over the mint limit'); + + // 一つだけならOK + const txParams2 = { value: ethers.utils.parseUnits("0.003", "ether") }; + await minter.connect(user5).functions.mintSelectedPrefecture(47, 1,txParams2); + + const [balance] = await token.functions.balanceOf(user5.address); + expect(balance.toNumber()).to.equal(1); // user1は1つ保持 + + await minter.functions.setMintMax(1500); + const [mintMax2] = await minter.functions.mintMax(); + expect(mintMax2.toNumber()).to.equal(1500); + }); + it('SetPrice', async function () { await expect(token.connect(user2).setPriceOf(tokenId1, price)).revertedWith('Only the onwer can set the price'); await token.connect(user1).setPriceOf(tokenId1, price);