From 86773c930bffefd78114ff0a3e85f1546e329b9c Mon Sep 17 00:00:00 2001 From: dappsar Date: Fri, 29 Dec 2023 16:19:13 -0300 Subject: [PATCH] [feat] :safety_vest: check if user has enough copies to burn with offer (#115) --- contracts/gamma/GammaCards.v5.sol | 37 +++++++------ contracts/gamma/GammaOffers.v4.sol | 1 - test/gamma.cards.test.ts | 88 ++++++++++++++++++++++++++---- 3 files changed, 99 insertions(+), 27 deletions(-) diff --git a/contracts/gamma/GammaCards.v5.sol b/contracts/gamma/GammaCards.v5.sol index 6889c22..e14094e 100644 --- a/contracts/gamma/GammaCards.v5.sol +++ b/contracts/gamma/GammaCards.v5.sol @@ -19,6 +19,7 @@ interface IgammaPacksContract { interface IgammaOffersContract { function hasOffer(address user, uint8 cardNumber) external view returns (bool); function removeOffersByUser(address user) external returns (bool); + function getOffersByUserCounter(address user) external view returns (uint256); function getOfferByUserAndCardNumber(address user, uint8 cardNumber) external view returns (uint256, uint8, uint8[] memory , address); } @@ -112,7 +113,7 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { secondaryUri = string(abi.encodePacked(bytes(baseUri), bytes("/"), bytes("121"), bytes("F.json"))); signersData.signers[_signer] = true; - for(uint256 i;i<122;i++){ + for(uint256 i; i<122; i++){ cardsInventory[i] = 1; } } @@ -170,11 +171,7 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { lotteryPrizePercentage = amount; } - function getLotteryPrize() public view returns (uint256) { - return (lotteryPrizePercentage * prizesBalance) / 100; - } - - function setUris(string memory newMainUri, string memory newSecondaryUri) public onlyOwners { + function setUris(string memory newMainUri, string memory newSecondaryUri) external onlyOwners { mainUri = newMainUri; secondaryUri = newSecondaryUri; emit NewUris(newMainUri, newSecondaryUri); @@ -225,6 +222,10 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { return signersData.signers[user]; } + function getLotteryPrize() public view returns (uint256) { + return (lotteryPrizePercentage * prizesBalance) / 100; + } + function getCardQuantityByUser(address user, uint8 cardNum) public view returns (uint8) { require(user != address(0), "Invalid address."); return cardsByUser[user][cardNum]; @@ -296,7 +297,7 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { gammaPacksContract.openPack(packNumber, user); prizesBalance += packPrice - packPrice / 6; - for(uint8 i;i= mainAlbumPrize, "Insufficient funds (contract)."); // check that you have at least one card of each number - // TO-REVIEW: check if this part is necessary because the subtraction of cards - // would cause underflow if it is at 0 bool unfinished; - for(uint8 i;i<=120;i++){ + for(uint8 i; i<=120; i++){ if(cardsByUser[msg.sender][i] == 0) { unfinished = true; break; @@ -407,23 +406,29 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { // the 60 cards album to 'burn' them. function burnCards(uint8[] calldata cardNumbers) public { require(cardsByUser[msg.sender][121] > 0, "You does not have any burning album."); - uint256 totalUserBurnedCards = burnedCards[msg.sender] + cardNumbers.length; bool mustPayPrize = false; if (totalUserBurnedCards >= 60) { require(prizesBalance >= secondaryAlbumPrize, "Insufficient funds (burnCards balance)."); - uint256 contractBalance = IERC20(DAI_TOKEN).balanceOf(address(this)); require(contractBalance >= secondaryAlbumPrize, "Insufficient funds (contract)."); - mustPayPrize = true; } - for(uint8 i;i 0); + for(uint8 i; i 0, "You does not have this card."); + if (userHasOffers) { + + if (gammaOffersContract.hasOffer(msg.sender, cardNumbers[i])) { + require(cardsByUser[msg.sender][cardNumbers[i]] >= 2, + "You cannot burn any more copies of this card."); + } + } cardsByUser[msg.sender][cardNumbers[i]]--; } + burnedCards[msg.sender] += cardNumbers.length; emit CardsBurned(msg.sender, cardNumbers); @@ -473,7 +478,7 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { } function testAddCards(address user) public onlyOwners { - for(uint8 i;i<=121;i++){ // 0-119: cards, 120: album-120, 121: album-60 + for(uint8 i; i<=121; i++){ // 0-119: cards, 120: album-120, 121: album-60 cardsByUser[user][i]++; } } @@ -482,7 +487,7 @@ contract NofGammaCardsV5 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { gammaPacksContract.openPack(packNumber, user); prizesBalance += packPrice - packPrice / 6; - for(uint8 i;i { @@ -131,7 +131,7 @@ describe('NoF - Gamma Cards Tests', function () { await gammaOffers.createOffer(uuidv4(), getCardsByUserResult[0][0], [1, 2, 24, 4, 5, 6, 7, 8]) let offers = await gammaOffers.getOffers() - await expect(offers.length).to.not.be.equal(0) + expect(offers.length).to.not.be.equal(0) await gammaCards.changeRequireOfferValidationInTransfer(true) await expect(gammaCards.transferCard(address1.address, getCardsByUserResult[0][0])).to.be.revertedWith( @@ -145,7 +145,7 @@ describe('NoF - Gamma Cards Tests', function () { await gammaOffers.createOffer(uuidv4(), getCardsByUserResult[0][0], [1, 2, 24, 4, 5, 6, 7, 8]) let offers = await gammaOffers.getOffers() - await expect(offers.length).to.not.be.equal(0) + expect(offers.length).to.not.be.equal(0) await gammaCards.changeRequireOfferValidationInTransfer(false) await gammaCards.transferCard(address1.address, getCardsByUserResult[0][0]) @@ -159,16 +159,16 @@ describe('NoF - Gamma Cards Tests', function () { const cardNumber = getCardsByUserResult1[0][0] let quantity = await gammaCards.getCardQuantityByUser(address0.address, cardNumber) - await expect(quantity).to.be.equal(2) + expect(quantity).to.be.equal(2) await gammaOffers.createOffer(uuidv4(), cardNumber, [1, 2, 24, 4, 5, 6, 7, 8]) let offers = await gammaOffers.getOffers() - await expect(offers.length).to.not.be.equal(0) + expect(offers.length).to.not.be.equal(0) await gammaCards.changeRequireOfferValidationInTransfer(true) await gammaCards.transferCard(address1.address, cardNumber) quantity = await gammaCards.getCardQuantityByUser(address0.address, cardNumber) - await expect(quantity).to.be.equal(1) + expect(quantity).to.be.equal(1) }) it('Should allow to transfer several cards', async () => { @@ -184,9 +184,9 @@ describe('NoF - Gamma Cards Tests', function () { const quantity1 = await gammaCards.getCardQuantityByUser(address0.address, cardNumber1) const quantity2 = await gammaCards.getCardQuantityByUser(address0.address, cardNumber2) const quantity3 = await gammaCards.getCardQuantityByUser(address0.address, cardNumber3) - await expect(quantity1).to.be.equal(0) - await expect(quantity2).to.be.equal(0) - await expect(quantity3).to.be.equal(0) + expect(quantity1).to.be.equal(0) + expect(quantity2).to.be.equal(0) + expect(quantity3).to.be.equal(0) }) it('Should allow to finish album', async () => { @@ -320,4 +320,72 @@ describe('NoF - Gamma Cards Tests', function () { expect(userFinalTokenBalance > userInitialTokenBalance).to.be.true expect(userTickets.length).greaterThan(0) }) + + it('Should allow to burn card with offer and more than 2 copies', async () => { + const { testDAI, gammaPacks, gammaCards, gammaOffers, gammaTickets, address0 } = + await loadFixture(deployNofGammaFixture) + + const amount = ethers.BigNumber.from('120000000000000000000') // 120 DAIs + await testDAI.approve(gammaPacks.address, amount) + await testDAI.approve(gammaCards.address, amount) + + await gammaPacks.buyPacks(10) // buy packs to increase prizesBalance in gamma cards; + + await gammaCards.testAddCards(address0.address) // 1 copy of each card + await gammaCards.testAddCards(address0.address) // 2 copies of each card + await gammaCards.testAddCards(address0.address) // 3 copies of each card + + const userCopiesCard1 = await gammaCards.getCardQuantityByUser(address0.address, 1); + expect(userCopiesCard1).to.be.equal(3) + + const userInitialTokenBalance = await testDAI.balanceOf(address0.address) + + const cardsToBurn = [] + for (let i = 1; i <= 60; i++) { + cardsToBurn.push(i); + } + + await gammaOffers.createOffer(uuidv4(), 1, [2, 24]) + let offers = await gammaOffers.getOffers() + expect(offers.length).to.not.be.equal(0) + + await gammaCards.burnCards(cardsToBurn) + const userFinalTokenBalance = await testDAI.balanceOf(address0.address) + const userTickets = await gammaTickets.getTicketsByUser(address0.address) + + expect(await gammaCards.hasCard(address0.address, 1)).to.be.true + expect(userFinalTokenBalance > userInitialTokenBalance).to.be.true + expect(userTickets.length).greaterThan(0) + }) + + it('Should revert when try to burn 2 copies of one card with offer and only 3 copies', async () => { + const { testDAI, gammaPacks, gammaCards, gammaOffers, address0 } = + await loadFixture(deployNofGammaFixture) + + const amount = ethers.BigNumber.from('120000000000000000000') // 120 DAIs + await testDAI.approve(gammaPacks.address, amount) + await testDAI.approve(gammaCards.address, amount) + + await gammaPacks.buyPacks(10) // buy packs to increase prizesBalance in gamma cards; + + await gammaCards.testAddCards(address0.address) // 1 copy of each card + await gammaCards.testAddCards(address0.address) // 2 copies of each card + await gammaCards.testAddCards(address0.address) // 3 copies of each card + + const userCopiesCard1 = await gammaCards.getCardQuantityByUser(address0.address, 1); + expect(userCopiesCard1).to.be.equal(3) + + const cardsToBurn = [1, 1] // 2 copies of card 1 + for (let i = 3; i <= 60; i++) { + cardsToBurn.push(i); + } + + await gammaOffers.createOffer(uuidv4(), 1, [2, 24]) + let offers = await gammaOffers.getOffers() + expect(offers.length).to.not.be.equal(0) + + expect(await gammaCards.burnCards(cardsToBurn)).to.be.revertedWith('You cannot burn any more copies of this card.') + }) + + })