diff --git a/.gas-snapshot b/.gas-snapshot index 8121701..d6eedf7 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -9,53 +9,54 @@ ACLManagerTest:testGrantRole() (gas: 23547) ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) -BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 164045) +BillboardTest:testAddToWhitelist() (gas: 37205) +BillboardTest:testApproveAndTransfer() (gas: 162759) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 424231, ~: 437543) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 389746) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 420946, ~: 434258) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386461) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 131697) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 605694) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139540) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13970) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145713) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 652059, ~: 658290) -BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129499) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162855) +BillboardTest:testCannotApproveByAttacker() (gas: 130412) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604409) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136255) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13993) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 142428) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650773, ~: 657004) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11861) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 128214) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 159548) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 134175) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129706) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 935690, ~: 935690) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 772282, ~: 772282) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 647468, ~: 647468) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 420497) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 742287, ~: 742287) +BillboardTest:testCannotTransferByOperator() (gas: 132890) +BillboardTest:testCannotTransferToZeroAddress() (gas: 128377) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11885) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934384, ~: 934384) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 770975, ~: 770975) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 646138, ~: 646138) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419189) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 740936, ~: 740936) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 650687) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2814114, ~: 1451611) -BillboardTest:testGetTokenURI() (gas: 156524) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649435) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1205928) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2877775, ~: 1456013) +BillboardTest:testGetTokenURI() (gas: 155305) BillboardTest:testMintBoard() (gas: 225991) BillboardTest:testMintBoardByWhitelist() (gas: 157825) BillboardTest:testMintBoardIfOpened() (gas: 130863) -BillboardTest:testPlaceBidByWhitelist() (gas: 473253) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 938084) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 488033, ~: 498752) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 767947, ~: 775021) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 765873, ~: 777549) -BillboardTest:testPlaceBidZeroPrice() (gas: 358961) -BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 142575) -BillboardTest:testSetBoardProperties() (gas: 308855) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 339487) -BillboardTest:testSetIsOpened() (gas: 15932) +BillboardTest:testPlaceBidByWhitelist() (gas: 469968) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 936799) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 486781, ~: 497500) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766505, ~: 773735) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764587, ~: 776263) +BillboardTest:testPlaceBidZeroPrice() (gas: 357676) +BillboardTest:testRemoveToWhitelist() (gas: 24939) +BillboardTest:testSafeTransferByOperator() (gas: 141290) +BillboardTest:testSetBoardProperties() (gas: 305548) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 338157) +BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testUpgradeRegistry() (gas: 2590942) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 936329, ~: 936329) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 510766, ~: 510766) +BillboardTest:testUpgradeRegistry() (gas: 2637423) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935022, ~: 935022) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509481, ~: 509481) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index c26e093..d813c76 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -168,6 +168,13 @@ contract Billboard is IBillboard { _clearAuction(tokenId_, _boardCreator, _nextAuctionId); } + /// @inheritdoc IBillboard + function clearAuctions(uint256[] calldata tokenIds_) external { + for (uint256 i = 0; i < tokenIds_.length; i++) { + clearAuction(tokenIds_[i]); + } + } + function _clearAuction(uint256 tokenId_, address boardCreator_, uint256 nextAuctionId_) private { IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, nextAuctionId_); IBillboardRegistry.Bid memory _highestBid = registry.getBid( diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index eec6db5..72b4f8c 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -142,6 +142,13 @@ interface IBillboard { */ function clearAuction(uint256 tokenId_) external; + /** + * @notice Clear the next auction of mutiple boards. + * + * @param tokenIds_ Token IDs of boards. + */ + function clearAuctions(uint256[] calldata tokenIds_) external; + /** * @notice Place bid for the next auction of a board. * diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 36dacf3..23fdabf 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -623,6 +623,80 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.isWithdrawn, false); } + function testClearAuctionsIfAuctionEnded() public { + (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); + (uint256 _tokenId2, uint256 _prevAuctionId2) = _mintBoardAndPlaceBid(); + + uint64 _placedAt = uint64(block.timestamp); + uint64 _clearedAt = uint64(block.timestamp) + registry.leaseTerm() + 1 minutes; + + // place bids + vm.startPrank(USER_A); + vm.deal(USER_A, 0); + operator.placeBid{value: 0}(_tokenId, 0); + + vm.startPrank(USER_B); + vm.deal(USER_B, 0); + operator.placeBid{value: 0}(_tokenId2, 0); + + // clear auction + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId, + _prevAuctionId + 1, + USER_A, + _clearedAt, + _clearedAt + registry.leaseTerm() + ); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId2, + _prevAuctionId2 + 1, + USER_B, + _clearedAt, + _clearedAt + registry.leaseTerm() + ); + + vm.warp(_clearedAt); + + uint256[] memory _tokenIds = new uint256[](2); + _tokenIds[0] = _tokenId; + _tokenIds[1] = _tokenId2; + operator.clearAuctions(_tokenIds); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.startAt, _placedAt); + assertEq(_auction.endAt, _placedAt + registry.leaseTerm()); + assertEq(_auction.leaseStartAt, _clearedAt); + assertEq(_auction.leaseEndAt, _clearedAt + registry.leaseTerm()); + assertEq(_auction.highestBidder, USER_A); + + uint256 _nextAuctionId2 = registry.nextBoardAuctionId(_tokenId2); + IBillboardRegistry.Auction memory _auction2 = registry.getAuction(_tokenId2, _nextAuctionId2); + assertEq(_auction2.startAt, _placedAt); + assertEq(_auction2.endAt, _placedAt + registry.leaseTerm()); + assertEq(_auction2.leaseStartAt, _clearedAt); + assertEq(_auction2.leaseEndAt, _clearedAt + registry.leaseTerm()); + assertEq(_auction2.highestBidder, USER_B); + + // check bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bid.price, 0); + assertEq(_bid.tax, 0); + assertEq(_bid.placedAt, _placedAt); + assertEq(_bid.isWon, true); + assertEq(_bid.isWithdrawn, false); + + IBillboardRegistry.Bid memory _bid2 = registry.getBid(_tokenId2, _nextAuctionId2, USER_B); + assertEq(_bid2.price, 0); + assertEq(_bid2.tax, 0); + assertEq(_bid2.placedAt, _placedAt); + assertEq(_bid2.isWon, true); + assertEq(_bid2.isWithdrawn, false); + } + function testCannotClearAuctionOnNewBoard() public { uint256 _mintedAt = block.timestamp; uint256 _clearedAt = _mintedAt + 1; diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 7a26dec..b866779 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -43,7 +43,6 @@ contract BillboardTestBase is Test { function _mintBoard() public returns (uint256 tokenId) { vm.prank(ADMIN); tokenId = operator.mintBoard(ADMIN); - assertEq(registry.balanceOf(ADMIN), 1); } function _mintBoardAndPlaceBid() public returns (uint256 tokenId, uint256 _nextAuctionId) {