From b0aae9c0f2563788c2d8d58b1d47b030e0e491a3 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 3 Jul 2024 11:52:53 +0800 Subject: [PATCH] test(billboard): add tests for auction & bids --- .gas-snapshot | 51 +-- src/Billboard/Billboard.sol | 55 ++- src/test/Billboard/BillboardTest.t.sol | 367 +++++++++------------ src/test/Billboard/BillboardTestBase.t.sol | 13 + 4 files changed, 213 insertions(+), 273 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 128f5d6..86e480f 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -9,29 +9,34 @@ ACLManagerTest:testGrantRole() (gas: 23547) ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) -BillboardTest:testAddToWhitelist() (gas: 252070) -BillboardTest:testApproveAndTransfer() (gas: 252645) -BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 225643) -BillboardTest:testCannotApproveByAttacker() (gas: 221634) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 459506) -BillboardTest:testCannotPlaceBidIfAuctionEnded() (gas: 598942) -BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 225773) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 218748) -BillboardTest:testCannotSetBoardByAttacker() (gas: 226787) -BillboardTest:testCannotSetBoardByOwner() (gas: 358929) -BillboardTest:testCannotTransferByOperator() (gas: 224012) -BillboardTest:testCannotTransferToZeroAddress() (gas: 219434) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 9016) -BillboardTest:testGetTokenURI() (gas: 388561) -BillboardTest:testMintBoard() (gas: 417198) -BillboardTest:testPlaceBid(uint96) (runs: 256, μ: 599051, ~: 601384) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 953951, ~: 953956) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 846964, ~: 850463) -BillboardTest:testPlaceBidZeroPrice() (gas: 416316) -BillboardTest:testRemoveToWhitelist() (gas: 238710) -BillboardTest:testSafeTransferByOperator() (gas: 232457) -BillboardTest:testSetBoardByCreator() (gas: 339338) -BillboardTest:testUpgradeRegistry() (gas: 3319574) +BillboardTest:testAddToWhitelist() (gas: 252168) +BillboardTest:testApproveAndTransfer() (gas: 252840) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 225830) +BillboardTest:testCannotApproveByAttacker() (gas: 221688) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 247623) +BillboardTest:testCannotClearAuctionIfNoBid() (gas: 255406) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 459863) +BillboardTest:testCannotPlaceBidIfAuctionEnded() (gas: 270366) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 225871) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 218868) +BillboardTest:testCannotSetBoardByAttacker() (gas: 226929) +BillboardTest:testCannotSetBoardByOwner() (gas: 359191) +BillboardTest:testCannotTransferByOperator() (gas: 224110) +BillboardTest:testCannotTransferToZeroAddress() (gas: 219554) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 9038) +BillboardTest:testClearAuction(uint96) (runs: 256, μ: 712150, ~: 712150) +BillboardTest:testClearAuctions() (gas: 1278587) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 4938705, ~: 2145225) +BillboardTest:testGetTokenURI() (gas: 388777) +BillboardTest:testMintBoard() (gas: 417504) +BillboardTest:testPlaceBid(uint96) (runs: 256, μ: 798108, ~: 800441) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 975862, ~: 975867) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 865951, ~: 869450) +BillboardTest:testPlaceBidZeroPrice() (gas: 416622) +BillboardTest:testRemoveToWhitelist() (gas: 238830) +BillboardTest:testSafeTransferByOperator() (gas: 232599) +BillboardTest:testSetBoardByCreator() (gas: 339600) +BillboardTest:testUpgradeRegistry() (gas: 3326886) 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 910e90c..d4faa64 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -137,7 +137,7 @@ contract Billboard is IBillboard { require(_board.creator != address(0), "Board not found"); uint256 _endedAt = this.getBlockFromEpoch(epoch_ + 1, _board.epochInterval); - require(_endedAt >= block.number, "Auction ended"); + require(block.number < _endedAt, "Auction ended"); IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, epoch_, msg.sender); @@ -189,36 +189,14 @@ contract Billboard is IBillboard { // revert if auction is still running uint256 _endedAt = this.getBlockFromEpoch(epoch_ + 1, _board.epochInterval); - require(block.number < _endedAt, "Auction not ended"); + require(block.number >= _endedAt, "Auction not ended"); - return _clearAuction(tokenId_, _board.creator, epoch_); - } - - /// @inheritdoc IBillboard - function clearAuctions( - uint256[] calldata tokenIds_, - uint256[] calldata epochs_ - ) external returns (address[] memory highestBidders, uint256[] memory prices, uint256[] memory taxes) { - uint256 _size = tokenIds_.length; - address[] memory _highestBidders = new address[](_size); - uint256[] memory _prices = new uint256[](_size); - uint256[] memory _taxes = new uint256[](_size); - - for (uint256 i = 0; i < _size; i++) { - (_highestBidders[i], _prices[i], _taxes[i]) = clearAuction(tokenIds_[i], epochs_[i]); - } - - return (_highestBidders, _prices, _taxes); - } - - function _clearAuction( - uint256 tokenId_, - address boardCreator_, - uint256 epoch_ - ) private returns (address highestBidder, uint256 price, uint256 tax) { address _highestBidder = registry.highestBidder(tokenId_, epoch_); IBillboardRegistry.Bid memory _highestBid = registry.getBid(tokenId_, epoch_, _highestBidder); + // revert if no bid + require(_highestBid.createdAt != 0, "No bid"); + // skip if auction is already cleared if (_highestBid.isWon) { return (address(0), 0, 0); @@ -231,8 +209,8 @@ contract Billboard is IBillboard { registry.transferCurrencyByOperator(_prevOwner, _highestBid.price); // transfer bid tax to board creator's tax treasury - (uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(boardCreator_); - registry.setTaxTreasury(boardCreator_, _taxAccumulated + _highestBid.tax, _taxWithdrawn); + (uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(_board.creator); + registry.setTaxTreasury(_board.creator, _taxAccumulated + _highestBid.tax, _taxWithdrawn); } // transfer ownership @@ -247,6 +225,23 @@ contract Billboard is IBillboard { return (_highestBidder, _highestBid.price, _highestBid.tax); } + /// @inheritdoc IBillboard + function clearAuctions( + uint256[] calldata tokenIds_, + uint256[] calldata epochs_ + ) external returns (address[] memory highestBidders, uint256[] memory prices, uint256[] memory taxes) { + uint256 _size = tokenIds_.length; + address[] memory _highestBidders = new address[](_size); + uint256[] memory _prices = new uint256[](_size); + uint256[] memory _taxes = new uint256[](_size); + + for (uint256 i = 0; i < _size; i++) { + (_highestBidders[i], _prices[i], _taxes[i]) = clearAuction(tokenIds_[i], epochs_[i]); + } + + return (_highestBidders, _prices, _taxes); + } + /// @inheritdoc IBillboard function getBid( uint256 tokenId_, @@ -294,7 +289,7 @@ contract Billboard is IBillboard { // revert if auction is not ended uint256 _endedAt = this.getBlockFromEpoch(epoch_ + 1, _board.epochInterval); - require(block.number < _endedAt, "Auction not ended"); + require(block.number >= _endedAt, "Auction not ended"); // revert if auction is not cleared address _highestBidder = registry.highestBidder(tokenId_, epoch_); diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 0474d6f..037f45d 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -191,8 +191,10 @@ contract BillboardTest is BillboardTestBase { uint256 _prevOperatorBalance = usdt.balanceOf(address(operator)); uint256 _prevRegistryBalance = usdt.balanceOf(address(registry)); - vm.prank(ADMIN); + vm.startPrank(ADMIN); operator.addToWhitelist(_tokenId, USER_A); + operator.addToWhitelist(_tokenId, USER_B); + vm.stopPrank(); vm.expectEmit(true, true, true, true); emit IBillboardRegistry.BidUpdated(_tokenId, _epoch, USER_A, _price, _tax, "", ""); @@ -214,6 +216,15 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.updatedAt, block.number); assertEq(_bid.isWon, false); assertEq(_bid.isWithdrawn, false); + + // bid with AD data + string memory _contentURI = "content URI"; + string memory _redirectURI = "redirect URI"; + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.BidUpdated(_tokenId, _epoch, USER_B, 0, 0, _contentURI, _redirectURI); + + vm.prank(USER_B); + operator.placeBid(_tokenId, _epoch, 0, _contentURI, _redirectURI); } function testPlaceBidWithSamePrices(uint96 _price) public { @@ -222,21 +233,12 @@ contract BillboardTest is BillboardTestBase { uint256 _tax = operator.calculateTax(_tokenId, _price); uint256 _total = _price + _tax; - vm.startPrank(ADMIN); - operator.addToWhitelist(_tokenId, USER_A); - operator.addToWhitelist(_tokenId, USER_B); - vm.stopPrank(); - // bid with USER_A - deal(address(usdt), USER_A, _total); - vm.prank(USER_A); - operator.placeBid(_tokenId, _epoch, _price); + _placeBid(_tokenId, _epoch, USER_A, _price); assertEq(registry.highestBidder(_tokenId, _epoch), USER_A); // bid with USER_B - deal(address(usdt), USER_B, _total); - vm.prank(USER_B); - operator.placeBid(_tokenId, _epoch, _price); + _placeBid(_tokenId, _epoch, USER_B, _price); assertEq(registry.highestBidder(_tokenId, _epoch), USER_A); // USER_A is still the same highest bidder // check bids @@ -258,35 +260,21 @@ contract BillboardTest is BillboardTestBase { (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); uint256 _tax = operator.calculateTax(_tokenId, _price); - uint256 _total = _price + _tax; - - vm.startPrank(ADMIN); - operator.addToWhitelist(_tokenId, USER_A); - operator.addToWhitelist(_tokenId, USER_B); - vm.stopPrank(); // bid with USER_A - deal(address(usdt), USER_A, _total); - vm.prank(USER_A); - operator.placeBid(_tokenId, _epoch, _price); + _placeBid(_tokenId, _epoch, USER_A, _price); assertEq(registry.highestBidder(_tokenId, _epoch), USER_A); // bid with USER_B uint256 _priceB = _price * 2; - uint256 _taxB = operator.calculateTax(_tokenId, _priceB); - uint256 _totalB = _priceB + _taxB; - deal(address(usdt), USER_B, _totalB); - vm.startPrank(USER_B); - operator.placeBid(_tokenId, _epoch, _priceB); + _placeBid(_tokenId, _epoch, USER_B, _priceB); assertEq(registry.highestBidder(_tokenId, _epoch), USER_B); // bid with USER_A uint256 _priceA = _price * 4; uint256 _taxA = operator.calculateTax(_tokenId, _priceA); uint256 _totalA = _priceA + _taxA; - deal(address(usdt), USER_A, _totalA); - vm.startPrank(USER_A); - operator.placeBid(_tokenId, _epoch, _priceA); + _placeBid(_tokenId, _epoch, USER_A, _priceA); assertEq(registry.highestBidder(_tokenId, _epoch), USER_A); // check balance of USER_A @@ -321,21 +309,19 @@ contract BillboardTest is BillboardTestBase { (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); uint256 _price = 1 ether; - uint256 _tax = operator.calculateTax(_tokenId, _price); - uint256 _total = _price + _tax; - deal(address(usdt), USER_A, _total); + + uint256 _endedAt = operator.getBlockFromEpoch(_epoch + 1, _board.epochInterval); vm.prank(ADMIN); operator.addToWhitelist(_tokenId, USER_A); vm.startPrank(USER_A); - operator.placeBid(_tokenId, _epoch, _price); - vm.roll(block.number + _board.epochInterval); + vm.roll(_endedAt); vm.expectRevert("Auction ended"); operator.placeBid(_tokenId, _epoch, _price); - vm.roll(block.number + _board.epochInterval + 1); + vm.roll(_endedAt + 1); vm.expectRevert("Auction ended"); operator.placeBid(_tokenId, _epoch, _price); } @@ -354,210 +340,151 @@ contract BillboardTest is BillboardTestBase { operator.placeBid(_tokenId, _epoch, _price); } - // function testClearAuctionIfAuctionEnded(uint96 _price) public { - // vm.assume(_price > 0.001 ether); - - // uint256 _tax = operator.calculateTax(_price); - // uint256 _total = _price + _tax; - - // (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); - // uint64 _placedAt = uint64(block.number); - // uint64 _clearedAt = uint64(block.number) + registry.leaseTerm() + 1; - - // // place a bid - // vm.startPrank(USER_A); - // deal(address(usdt), USER_A, _total); - // operator.placeBid(_tokenId, _price); - - // // clear auction - // vm.expectEmit(true, true, true, true); - // emit IBillboardRegistry.AuctionCleared( - // _tokenId, - // _prevAuctionId + 1, - // USER_A, - // _clearedAt, - // _clearedAt + registry.leaseTerm() - // ); - - // vm.roll(_clearedAt); - // (uint256 _price1, uint256 _tax1) = operator.clearAuction(_tokenId); - // assertEq(_price1, _price); - // assertEq(_tax1, _tax); - - // // 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); - - // // check bid - // IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); - // assertEq(_bid.price, _price); - // assertEq(_bid.tax, _tax); - // assertEq(_bid.placedAt, _placedAt); - // assertEq(_bid.isWon, true); - // assertEq(_bid.isWithdrawn, false); - // } - - // function testClearAuctionsIfAuctionEnded() public { - // (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); - // (uint256 _tokenId2, uint256 _prevAuctionId2) = _mintBoardAndPlaceBid(); - - // uint64 _placedAt = uint64(block.number); - // uint64 _clearedAt = uint64(block.number) + registry.leaseTerm() + 1; + function testClearAuction(uint96 _price) public { + vm.assume(_price > 0.001 ether); - // // place bids - // vm.startPrank(USER_A); - // deal(address(usdt), USER_A, 0); - // operator.placeBid(_tokenId, 0); - - // vm.startPrank(USER_B); - // deal(address(usdt), USER_B, 0); - // operator.placeBid(_tokenId2, 0); + (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); + uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); + uint256 _tax = operator.calculateTax(_tokenId, _price); + uint256 _placedAt = block.number; + uint256 _clearedAt = operator.getBlockFromEpoch(_epoch + 1, _board.epochInterval); - // // 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.roll(_clearedAt); - - // uint256[] memory _tokenIds = new uint256[](2); - // _tokenIds[0] = _tokenId; - // _tokenIds[1] = _tokenId2; - // (uint256[] memory prices, uint256[] memory taxes) = operator.clearAuctions(_tokenIds); - // assertEq(prices[0], 0); - // assertEq(prices[1], 0); - // assertEq(taxes[0], 0); - // assertEq(taxes[1], 0); + // place bid + _placeBid(_tokenId, _epoch, USER_A, _price); - // // 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); + // clear auction + vm.expectEmit(true, true, true, false); + emit IBillboardRegistry.AuctionCleared(_tokenId, _epoch, 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); + vm.roll(_clearedAt); + (address _highestBidder, uint256 _price1, uint256 _tax1) = operator.clearAuction(_tokenId, _epoch); - // // 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); - // } + assertEq(_price1, _price); + assertEq(_tax1, _tax); + assertEq(_highestBidder, registry.highestBidder(_tokenId, _epoch)); + assertEq(_highestBidder, USER_A); - // function testCannotClearAuctionOnNewBoard() public { - // uint256 _mintedAt = block.number; - // uint256 _clearedAt = _mintedAt + 1; - // (uint256 _tokenId,) = _mintBoard(); + // check auction & bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _epoch, USER_A); + assertEq(_bid.price, _price); + assertEq(_bid.tax, _tax); + assertEq(_bid.createdAt, _placedAt); + assertEq(_bid.isWon, true); + assertEq(_bid.isWithdrawn, false); - // vm.startPrank(ADMIN); + // check balances + assertEq(usdt.balanceOf(address(registry)), _tax); + assertEq(usdt.balanceOf(ADMIN), _price); + assertEq(usdt.balanceOf(USER_A), 0); + } - // // clear auction - // vm.roll(_clearedAt); - // vm.expectRevert("Auction not found"); - // operator.clearAuction(_tokenId); - // } + function testClearAuctions() public { + (uint256 _tokenId1, IBillboardRegistry.Board memory _board1) = _mintBoard(); + (uint256 _tokenId2, IBillboardRegistry.Board memory _board2) = _mintBoard(); + uint256 _epoch1 = operator.getEpochFromBlock(block.number, _board1.epochInterval); + uint256 _epoch2 = operator.getEpochFromBlock(block.number, _board2.epochInterval); + _placeBid(_tokenId1, _epoch1, USER_A, 1 ether); + _placeBid(_tokenId2, _epoch2, USER_B, 1 ether); - // function testCannotClearAuctionIfAuctionNotEnded() public { - // (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _clearedAt = operator.getBlockFromEpoch(_epoch1 + 1, _board1.epochInterval); - // // place a bid - // vm.startPrank(USER_A); - // deal(address(usdt), USER_A, 0); - // operator.placeBid(_tokenId, 0); - - // // try to clear auction - // vm.expectRevert("Auction not ended"); - // operator.clearAuction(_tokenId); + // clear auctions + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared(_tokenId1, _epoch1, USER_A); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared(_tokenId2, _epoch2, USER_B); + + vm.roll(_clearedAt); + + uint256[] memory _tokenIds = new uint256[](2); + uint256[] memory _epochs = new uint256[](2); + _tokenIds[0] = _tokenId1; + _tokenIds[1] = _tokenId2; + _epochs[0] = _epoch1; + _epochs[1] = _epoch2; + (address[] memory highestBidders, , ) = operator.clearAuctions(_tokenIds, _epochs); + assertEq(highestBidders[0], USER_A); + assertEq(highestBidders[1], USER_B); + + // check auction & bids + IBillboardRegistry.Bid memory _bid1 = registry.getBid(_tokenId1, _epoch1, USER_A); + assertEq(_bid1.isWon, true); + + IBillboardRegistry.Bid memory _bid2 = registry.getBid(_tokenId2, _epoch2, USER_B); + assertEq(_bid2.isWon, true); + } - // vm.roll(block.number + registry.leaseTerm() - 1); - // vm.expectRevert("Auction not ended"); - // operator.clearAuction(_tokenId); - // } + function testCannotClearAuctionIfAuctionNotEnded() public { + (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); + uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); + uint256 _endedAt = operator.getBlockFromEpoch(_epoch + 1, _board.epochInterval); - // function testGetBids(uint8 _bidCount, uint8 _limit, uint8 _offset) public { - // vm.assume(_bidCount > 0); - // vm.assume(_bidCount <= 64); - // vm.assume(_limit <= _bidCount); - // vm.assume(_offset <= _limit); + vm.expectRevert("Auction not ended"); + operator.clearAuction(_tokenId, _epoch); - // (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + vm.roll(_endedAt - 1); + vm.expectRevert("Auction not ended"); + operator.clearAuction(_tokenId, _epoch); + } - // for (uint8 i = 0; i < _bidCount; i++) { - // address _bidder = address(uint160(2000 + i)); + function testCannotClearAuctionIfNoBid() public { + (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); + uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); + uint256 _clearedAt = operator.getBlockFromEpoch(_epoch + 1, _board.epochInterval); - // vm.prank(ADMIN); - // operator.addToWhitelist(_bidder); + vm.roll(_clearedAt); + vm.expectRevert("No bid"); + operator.clearAuction(_tokenId, _epoch); + } - // uint256 _price = 1 ether + i; - // uint256 _tax = operator.calculateTax(_price); - // uint256 _totalAmount = _price + _tax; + function testGetBids(uint8 _bidCount, uint8 _limit, uint8 _offset) public { + vm.assume(_bidCount > 0); + vm.assume(_bidCount <= 64); + vm.assume(_limit <= _bidCount); + vm.assume(_offset <= _limit); - // deal(address(usdt), _bidder, _totalAmount); - // vm.startPrank(_bidder); - // usdt.approve(address(operator), _totalAmount); - // operator.placeBid(_tokenId, _price); - // vm.stopPrank(); - // } + (uint256 _tokenId, IBillboardRegistry.Board memory _board) = _mintBoard(); + uint256 _epoch = operator.getEpochFromBlock(block.number, _board.epochInterval); - // // get bids - // uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); - // (uint256 _t, uint256 _l, uint256 _o, IBillboardRegistry.Bid[] memory _bids) = operator.getBids( - // _tokenId, - // _nextAuctionId, - // _limit, - // _offset - // ); - // uint256 _left = _t - _offset; - // uint256 _size = _left > _limit ? _limit : _left; - // assertEq(_t, _bidCount); - // assertEq(_l, _limit); - // assertEq(_bids.length, _size); - // assertEq(_o, _offset); - // for (uint256 i = 0; i < _size; i++) { - // uint256 _price = 1 ether + _offset + i; - // assertEq(_bids[i].price, _price); - // } - // } + for (uint8 i = 0; i < _bidCount; i++) { + address _bidder = address(uint160(2000 + i)); + + vm.prank(ADMIN); + operator.addToWhitelist(_tokenId, _bidder); + + uint256 _price = 1 ether + i; + uint256 _tax = operator.calculateTax(_tokenId, _price); + uint256 _totalAmount = _price + _tax; + + deal(address(usdt), _bidder, _totalAmount); + vm.startPrank(_bidder); + usdt.approve(address(operator), _totalAmount); + operator.placeBid(_tokenId, _epoch, _price); + vm.stopPrank(); + } + + // get bids + (uint256 _t, uint256 _l, uint256 _o, IBillboardRegistry.Bid[] memory _bids) = operator.getBids( + _tokenId, + _epoch, + _limit, + _offset + ); + uint256 _left = _t - _offset; + uint256 _size = _left > _limit ? _limit : _left; + assertEq(_t, _bidCount); + assertEq(_l, _limit); + assertEq(_bids.length, _size); + assertEq(_o, _offset); + for (uint256 i = 0; i < _size; i++) { + uint256 _price = 1 ether + _offset + i; + assertEq(_bids[i].price, _price); + } + } - // ////////////////////////////// - // /// Tax & Withdraw - // ////////////////////////////// + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// // function testCalculateTax() public { // uint256 _price = 100; diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 4c2515e..c7ab1c3 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -62,4 +62,17 @@ contract BillboardTestBase is Test { tokenId = operator.mintBoard(TAX_RATE, EPOCH_INTERVAL); board = registry.getBoard(tokenId); } + + function _placeBid(uint256 _tokenId, uint256 _epoch, address _bidder, uint256 _price) public { + uint256 _tax = operator.calculateTax(_tokenId, _price); + uint256 _total = _price + _tax; + + deal(address(usdt), _bidder, _total); + + vm.prank(ADMIN); + operator.addToWhitelist(_tokenId, _bidder); + + vm.prank(_bidder); + operator.placeBid(_tokenId, _epoch, _price); + } }