From 74c6a472e1d8c5a480196dcc1714550f292efef2 Mon Sep 17 00:00:00 2001 From: lpopo0856 Date: Fri, 14 Jul 2023 16:11:27 +0800 Subject: [PATCH 1/5] Check if seriesId duplicate with other seriesId --- contracts/FeralfileArtworkV4.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/FeralfileArtworkV4.sol b/contracts/FeralfileArtworkV4.sol index 31e4c8d..c2974ce 100644 --- a/contracts/FeralfileArtworkV4.sol +++ b/contracts/FeralfileArtworkV4.sol @@ -130,6 +130,12 @@ contract FeralfileExhibitionV4 is // initialize max supply map for (uint256 i = 0; i < seriesIds_.length; i++) { + // Check duplicate with others + for (uint256 j = i + 1; j < seriesIds_.length; j++) { + if (seriesIds_[i] == seriesIds_[j]) { + revert("FeralfileExhibitionV4: duplicate seriesId"); + } + } require( seriesMaxSupplies_[i] > 0, "FeralfileExhibitionV4: zero max supply" From e220d1bedab9a366bd0f6d8cba2c0e51ddd23cc5 Mon Sep 17 00:00:00 2001 From: lpopo0856 Date: Fri, 14 Jul 2023 17:52:36 +0800 Subject: [PATCH 2/5] Fix the wasted eth transfer problem --- contracts/FeralfileArtworkV4.sol | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/contracts/FeralfileArtworkV4.sol b/contracts/FeralfileArtworkV4.sol index c2974ce..7114a2d 100644 --- a/contracts/FeralfileArtworkV4.sol +++ b/contracts/FeralfileArtworkV4.sol @@ -446,6 +446,11 @@ contract FeralfileExhibitionV4 is ) { uint256 rev = (itemRevenue * saleData_.revenueShares[i][j].bps) / 10000; + if ( + saleData_.revenueShares[i][j].recipient == costReceiver + ) { + continue; + } distributedRevenue += rev; payable(saleData_.revenueShares[i][j].recipient).transfer( rev @@ -456,10 +461,10 @@ contract FeralfileExhibitionV4 is emit BuyArtwork(saleData_.destination, saleData_.tokenIds[i]); } - // Transfer cost and remaining funds - uint256 cost = saleData_.price - distributedRevenue; - if (cost > 0) { - payable(costReceiver).transfer(cost); + // Transfer cost, platform revenue and remaining funds + uint256 leftOver = saleData_.price - distributedRevenue; + if (leftOver > 0) { + payable(costReceiver).transfer(leftOver); } } From bd4be38b150a6784fe71a3f70a698425bb857155 Mon Sep 17 00:00:00 2001 From: lpopo0856 Date: Mon, 17 Jul 2023 10:38:05 +0800 Subject: [PATCH 3/5] Add test & remove withdraw fund feature --- contracts/FeralfileArtworkV4.sol | 5 ----- test/feralfile_exhibition_v4.js | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/contracts/FeralfileArtworkV4.sol b/contracts/FeralfileArtworkV4.sol index 7114a2d..7e14b9d 100644 --- a/contracts/FeralfileArtworkV4.sol +++ b/contracts/FeralfileArtworkV4.sol @@ -607,11 +607,6 @@ contract FeralfileExhibitionV4 is ); } - /// @notice withdraw all fund - function withdrawFunds() external onlyOwner { - payable(msg.sender).transfer(address(this).balance); - } - /// @notice Event emitted when new Artwork has been minted event NewArtwork( address indexed owner, diff --git a/test/feralfile_exhibition_v4.js b/test/feralfile_exhibition_v4.js index fc44239..61e2aef 100644 --- a/test/feralfile_exhibition_v4.js +++ b/test/feralfile_exhibition_v4.js @@ -66,6 +66,32 @@ contract("FeralfileExhibitionV4_0", async (accounts) => { assert.equal(seriesTotalSupply1, 0); }); + it("test duplicate series in constructor", async function () { + // Deploy contract with duplicate series defined + let seriesIds = [0, 1, 2, 3, 1]; + let seriesMaxSupply = [1, 1, 100, 1000, 10000]; + try { + await FeralfileExhibitionV4.new( + "Feral File V4 Test", + "FFv4", + true, + true, + this.signer, + this.vault.address, + COST_RECEIVER, + CONTRACT_URI, + seriesIds, + seriesMaxSupply + ); + } catch (error) { + assert.ok( + error.message.includes( + "FeralfileExhibitionV4: duplicate seriesId" + ) + ); + } + }) + it("test mint artwork", async function () { const contract = this.contracts[0]; From a140159a77944f217b6b76af0f58d4125b3445fa Mon Sep 17 00:00:00 2001 From: lpopo0856 Date: Mon, 17 Jul 2023 11:15:08 +0800 Subject: [PATCH 4/5] Add check&test for total bps over 10k --- contracts/FeralfileArtworkV4.sol | 6 ++ test/feralfile_exhibition_v4.js | 113 ++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/contracts/FeralfileArtworkV4.sol b/contracts/FeralfileArtworkV4.sol index 7e14b9d..745d88c 100644 --- a/contracts/FeralfileArtworkV4.sol +++ b/contracts/FeralfileArtworkV4.sol @@ -461,6 +461,12 @@ contract FeralfileExhibitionV4 is emit BuyArtwork(saleData_.destination, saleData_.tokenIds[i]); } + require( + saleData_.price >= distributedRevenue && + saleData_.price - distributedRevenue >= saleData_.cost, + "FeralfileExhibitionV4: total bps over 10,000" + ); + // Transfer cost, platform revenue and remaining funds uint256 leftOver = saleData_.price - distributedRevenue; if (leftOver > 0) { diff --git a/test/feralfile_exhibition_v4.js b/test/feralfile_exhibition_v4.js index 61e2aef..c4e2645 100644 --- a/test/feralfile_exhibition_v4.js +++ b/test/feralfile_exhibition_v4.js @@ -15,7 +15,7 @@ contract("FeralfileExhibitionV4_0", async (accounts) => { // Deploy multiple contracts this.contracts = []; - for (let i = 0; i < 7; i++) { + for (let i = 0; i < 8; i++) { let contract = await FeralfileExhibitionV4.new( "Feral File V4 Test", "FFv4", @@ -583,6 +583,117 @@ contract("FeralfileExhibitionV4_0", async (accounts) => { } }); + it("test buy artworks failed with total bps over 10k", async function () { + let contract = this.contracts[7]; + + // Mint for buy by crypto + let owner = contract.address; + await contract.mintArtworks([ + [this.seriesIds[3], 3000000, owner], + [this.seriesIds[3], 3000001, owner], + [this.seriesIds[4], 4000000, owner], + [this.seriesIds[4], 4000001, owner], + [this.seriesIds[4], 4000002, owner], + ]); + + // Generate signature + const expiryTime = (new Date().getTime() / 1000 + 300).toFixed(0); + const signParams = web3.eth.abi.encodeParameters( + [ + "uint", + "address", + "tuple(uint256,uint256,uint256,address,uint256[],tuple(address,uint256)[][],bool)", + ], + [ + BigInt(await web3.eth.getChainId()).toString(), + contract.address, + [ + BigInt(0.25 * 1e18).toString(), + BigInt(0.02 * 1e18).toString(), + expiryTime, + accounts[2], + [3000000, 3000001, 4000000, 4000001, 4000002], + [ + [ + [accounts[3], 8001], + [accounts[4], 2000], + ], + [ + [accounts[3], 8001], + [accounts[4], 2000], + ], + [ + [accounts[3], 9000], + [accounts[4], 2000], + ], + [ + [accounts[3], 9000], + [accounts[4], 2000], + ], + [ + [accounts[3], 8500], + [accounts[4], 2000], + ], + ], + false, + ], + ] + ); + const hash = web3.utils.keccak256(signParams); + var sig = await web3.eth.sign(hash, this.signer); + sig = sig.substr(2); + const r = "0x" + sig.slice(0, 64); + const s = "0x" + sig.slice(64, 128); + const v = "0x" + sig.slice(128, 130); + // Generate signature + + try { + await contract.startSale(); + await contract.buyArtworks( + r, + s, + web3.utils.toDecimal(v) + 27, // magic 27 + [ + BigInt(0.25 * 1e18).toString(), + BigInt(0.02 * 1e18).toString(), + expiryTime, + accounts[2], + [3000000, 3000001, 4000000, 4000001, 4000002], + [ + [ + [accounts[3], 8001], + [accounts[4], 2000], + ], + [ + [accounts[3], 8001], + [accounts[4], 2000], + ], + [ + [accounts[3], 9000], + [accounts[4], 2000], + ], + [ + [accounts[3], 9000], + [accounts[4], 2000], + ], + [ + [accounts[3], 8500], + [accounts[4], 2000], + ], + ], + false, + ], + { from: accounts[5], value: 0.25 * 1e18 } + ); + } catch (error) { + assert.ok( + error.message.includes( + "FeralfileExhibitionV4: total bps over 10,000" + ) + ); + } + }); + it("test start/stop and burn, pause/resume sale", async function () { const contract = this.contracts[4]; From 8ec094faf8520994c82ed538877a8101be207212 Mon Sep 17 00:00:00 2001 From: lpopo0856 Date: Mon, 17 Jul 2023 11:46:22 +0800 Subject: [PATCH 5/5] better condition --- contracts/FeralfileArtworkV4.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/FeralfileArtworkV4.sol b/contracts/FeralfileArtworkV4.sol index 745d88c..be58f1f 100644 --- a/contracts/FeralfileArtworkV4.sol +++ b/contracts/FeralfileArtworkV4.sol @@ -462,8 +462,7 @@ contract FeralfileExhibitionV4 is } require( - saleData_.price >= distributedRevenue && - saleData_.price - distributedRevenue >= saleData_.cost, + saleData_.price - saleData_.cost >= distributedRevenue, "FeralfileExhibitionV4: total bps over 10,000" );