diff --git a/contracts/token/erc1155/NFT1155SubscriptionUpgradeable.sol b/contracts/token/erc1155/NFT1155SubscriptionUpgradeable.sol index 663bceec..ebacbbf7 100644 --- a/contracts/token/erc1155/NFT1155SubscriptionUpgradeable.sol +++ b/contracts/token/erc1155/NFT1155SubscriptionUpgradeable.sol @@ -56,9 +56,13 @@ contract NFT1155SubscriptionUpgradeable is NFT1155Upgradeable { function burn(uint256 id, uint256 amount) override public { burn(_msgSender(), id, amount); - } - + } + function burn(address to, uint256 id, uint256 amount) override public { + burn(to, id, amount, 0); + } + + function burn(address to, uint256 id, uint256 amount, uint256 seed) override public { require(balanceOf(to, id) >= amount, 'ERC1155: burn amount exceeds balance'); require( isOperator(_msgSender()) || // Or the DIDRegistry is burning the NFT @@ -72,7 +76,7 @@ contract NFT1155SubscriptionUpgradeable is NFT1155Upgradeable { _nftAttributes[id].nftSupply -= amount; // Register provenance event nftRegistry.used( - keccak256(abi.encode(id, _msgSender(), 'burn', amount, block.number)), + keccak256(abi.encode(id, _msgSender(), 'burn', amount, block.number, seed, _nftAttributes[id].nftSupply)), bytes32(id), _msgSender(), keccak256('burn'), '', 'burn'); bytes32 _key = _getTokenKey(to, id); @@ -153,7 +157,7 @@ contract NFT1155SubscriptionUpgradeable is NFT1155Upgradeable { ) external { require(ids.length == amounts.length, 'burnBatch: lengths do not match'); for (uint i = 0; i < ids.length; i++) { - burn(from, ids[i], amounts[i]); + burn(from, ids[i], amounts[i], i); } } } diff --git a/contracts/token/erc1155/NFT1155Upgradeable.sol b/contracts/token/erc1155/NFT1155Upgradeable.sol index a3866f58..92dc67da 100644 --- a/contracts/token/erc1155/NFT1155Upgradeable.sol +++ b/contracts/token/erc1155/NFT1155Upgradeable.sol @@ -142,7 +142,7 @@ contract NFT1155Upgradeable is ERC1155Upgradeable, NFTBase { _nftAttributes[id].nftSupply += amount; // Register provenance event nftRegistry.used( - keccak256(abi.encode(id, _msgSender(), 'mint', amount, block.number)), + keccak256(abi.encode(id, _msgSender(), 'mint', amount, block.number, _nftAttributes[id].nftSupply, data)), bytes32(id), _msgSender(), keccak256('mint'), '', 'mint'); _mint(to, id, amount, data); @@ -151,8 +151,12 @@ contract NFT1155Upgradeable is ERC1155Upgradeable, NFTBase { function burn(uint256 id, uint256 amount) virtual public { burn(_msgSender(), id, amount); } - + function burn(address to, uint256 id, uint256 amount) virtual public { + burn(to, id, amount, 0); + } + + function burn(address to, uint256 id, uint256 amount, uint256 seed) virtual public { require(balanceOf(to, id) >= amount, 'ERC1155: burn amount exceeds balance'); require( isOperator(_msgSender()) || // Or the DIDRegistry is burning the NFT @@ -166,7 +170,7 @@ contract NFT1155Upgradeable is ERC1155Upgradeable, NFTBase { _nftAttributes[id].nftSupply -= amount; // Register provenance event nftRegistry.used( - keccak256(abi.encode(id, _msgSender(), 'burn', amount, block.number)), + keccak256(abi.encode(id, _msgSender(), 'burn', amount, block.number, seed, _nftAttributes[id].nftSupply)), bytes32(id), _msgSender(), keccak256('burn'), '', 'burn'); _burn(to, id, amount); diff --git a/package.json b/package.json index 2c000e38..839fa3fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nevermined-io/contracts", - "version": "3.5.5", + "version": "3.5.6", "description": "Nevermined implementation of Nevermined in Solidity", "bugs": { "url": "https://github.com/nevermined-io/contracts/issues" diff --git a/test/unit/token/NFT1155Subscription.Test.js b/test/unit/token/NFT1155Subscription.Test.js index c5b5c88d..8f16c7d0 100644 --- a/test/unit/token/NFT1155Subscription.Test.js +++ b/test/unit/token/NFT1155Subscription.Test.js @@ -331,5 +331,30 @@ contract('NFT1155 Subscription', (accounts) => { } assert.strictEqual(minted.length, 4) }) + + it('Multiple tokens can be burned without generating provenance issues', async () => { + await setupTest() + + const didSeed5 = testUtils.generateId() + const tokenId5 = await didRegistry.hashDID(didSeed5, minter) + await didRegistry.methods[ + 'registerMintableDID(bytes32,address,bytes32,address[],string,uint256,uint256,bool,bytes32,string,string)' + ](didSeed5, nft.address, checksum, [], url, 0, 0, false, constants.activities.GENERATED, '', '', { from: minter }) + + const currentBlockNumber = await ethers.provider.getBlockNumber() + + // We MINT 10 tokens + await nft.methods[ + 'mint(address,uint256,uint256,uint256,bytes)' + ](account2, tokenId5, 10, currentBlockNumber + blocksExpiring, data, { from: minter }) + + // We BURN 1 tokens 2 times + await nft.burnBatch(account2, [tokenId5, tokenId5], [1, 1], { from: minter }) + await increaseTime.mineBlocks(web3, 2) + + // Balance is 8 + const balance = new BigNumber(await nft.balanceOf(account2, tokenId5)) + assert.strictEqual(balance.toNumber(), 10 - 2) + }) }) })