diff --git a/] b/] deleted file mode 100644 index c14745991..000000000 --- a/] +++ /dev/null @@ -1,16 +0,0 @@ -## Things to do this week - -- [ ] pay credid card bill -- [ ] pay energy bill -- [ ] levar calças para a costureira -- [ ] comprar - - varal - - organizador de gaveta - - torneira eletrica - -## Remember - -- [ ] Ligar ar condicionado do escritório -- [ ] Levar Theo pra tomar banho - - diff --git a/contracts/protocol/facets/ExchangeHandlerFacet.sol b/contracts/protocol/facets/ExchangeHandlerFacet.sol index d3540013d..cf8ac2b74 100644 --- a/contracts/protocol/facets/ExchangeHandlerFacet.sol +++ b/contracts/protocol/facets/ExchangeHandlerFacet.sol @@ -809,29 +809,32 @@ contract ExchangeHandlerFacet is IBosonExchangeHandler, BuyerBase, DisputeBase { TokenRange[] storage twinRanges = lookups.twinRangesBySeller[seller.id][twin.tokenAddress]; uint256 lastIndex = twinRanges.length - 1; + // Find the range that contains the twin for (uint256 j = 0; j <= lastIndex; j++) { - if (twinRanges[j].start <= twin.tokenId && twinRanges[j].end >= twin.tokenId) { - // If twin is the last one in the range, remove the range - if (twinRanges[j].end == twin.tokenId) { - // If not removing last element, move the last to the removed index + if (twinRanges[j].start <= tokenId && twinRanges[j].end >= tokenId) { + bool unlimitedSupply = twin.supplyAvailable == type(uint256).max; + + // Limited: Order is descending first tokenId is the last one to be transferred + // Unlimited: Order is ascending first tokenId is the first one to be transferred + if ((unlimitedSupply ? twinRanges[j].end : twinRanges[j].start) == tokenId) { + // Remove from ranges mapping if (j != lastIndex) { twinRanges[j] = twinRanges[lastIndex]; } - // Remove last element twinRanges.pop(); - } else { - // If twin has limited supply - if (twin.supplyAvailable != type(uint256).max) { - // Reduce end property - twinRanges[j].end--; - } else { - // Otherwise, increase start property - twinRanges[j].start++; - } break; } + + // If twin has unlimited supply + if (unlimitedSupply) { + // Increase start property + twinRanges[j].start++; + } else { + // Otherwise reduce end property + twinRanges[j].end--; + } } } } diff --git a/test/protocol/ExchangeHandlerTest.js b/test/protocol/ExchangeHandlerTest.js index f91af94d9..419167dfc 100644 --- a/test/protocol/ExchangeHandlerTest.js +++ b/test/protocol/ExchangeHandlerTest.js @@ -2474,6 +2474,59 @@ describe("IBosonExchangeHandler", function () { expect(range).to.deep.equal(expectedRange); }); + it("Should remove element from range when transfering last twin", async function () { + // starting slot + const protocolLookupsSlot = keccak256(ethers.utils.toUtf8Bytes("boson.protocol.lookups")); + const protocolLookupsSlotNumber = ethers.BigNumber.from(protocolLookupsSlot); + + // seller id mapping from twinRangesBySeller + const firstMappingSlot = ethers.BigNumber.from( + getMappingStoragePosition( + protocolLookupsSlotNumber.add("22"), + ethers.BigNumber.from(seller.id).toNumber(), + paddingType.START + ) + ); + + // token address mapping from twinRangesBySeller + const secondMappingSlot = getMappingStoragePosition( + firstMappingSlot, + twin721.tokenAddress.toLowerCase(), + paddingType.START + ); + + const range = {}; + const arrayStart = ethers.BigNumber.from(keccak256(secondMappingSlot)); + let exchangeId = 1; + let supply = 9; + + // redeem first exchange and increase exchangeId + await exchangeHandler.connect(buyer).redeemVoucher(exchangeId++); + + while (exchangeId <= 10) { + await exchangeHandler.connect(buyer).commitToOffer(buyer.address, offerId, { value: price }); + + await exchangeHandler.connect(buyer).redeemVoucher(exchangeId); + + range.start = await getStorageAt(protocolDiamondAddress, arrayStart.add(0)); + range.end = await getStorageAt(protocolDiamondAddress, arrayStart.add(1)); + + let expectedRange = {}; + if (exchangeId == 10) { + // Last transfer should remove range + expectedRange.start = ethers.utils.hexZeroPad(ethers.BigNumber.from("0").toHexString(), 32); + expectedRange.end = ethers.utils.hexZeroPad(ethers.BigNumber.from("0").toHexString(), 32); + } else { + expectedRange.start = ethers.utils.hexZeroPad(ethers.BigNumber.from("1").toHexString(), 32); + expectedRange.end = ethers.utils.hexZeroPad(ethers.BigNumber.from(--supply).toHexString(), 32); + } + + expect(range).to.deep.equal(expectedRange); + + exchangeId++; + } + }); + context("Unlimited supply", async function () { let other721; beforeEach(async function () { @@ -2501,6 +2554,9 @@ describe("IBosonExchangeHandler", function () { twin721.id = "4"; twin721.tokenId = "1"; + // Increase exchange id + exchange.id++; + // Create a new twin with the new token address await twinHandler.connect(assistant).createTwin(twin721.toStruct()); @@ -2527,7 +2583,7 @@ describe("IBosonExchangeHandler", function () { }); it("Transfer token order must be ascending if twin supply is unlimited", async function () { - let exchangeId = ++exchange.id; + let exchangeId = exchange.id; // tokenId transferred to the buyer is 1 let expectedTokenId = "1"; @@ -2554,6 +2610,7 @@ describe("IBosonExchangeHandler", function () { // Commit to offer for the second time await exchangeHandler.connect(buyer).commitToOffer(buyer.address, offerId, { value: price }); + console.log("transferring second exchange"); // Redeem the voucher // tokenId transferred to the buyer is 1 await expect(exchangeHandler.connect(buyer).redeemVoucher(++exchangeId)) @@ -2565,7 +2622,7 @@ describe("IBosonExchangeHandler", function () { expect(owner).to.equal(buyer.address); }); - it.only("Should increase start in twinRangesBySeller range", async function () { + it("Should increase start in twinRangesBySeller range", async function () { // Redeem the voucher await exchangeHandler.connect(buyer).redeemVoucher(exchange.id);