Inaccurate value is used for partial fill quote amount when calculating fees
Inaccurate value is used for partial fill quote amount when calculating fees which can cause reward claiming / payment withdrawal to revert\\nThe fees of an auction is managed as follows:\\nWhenever a bidder claims their payout, calculate the amount of quote tokens that should be collected as fees (instead of giving the entire quote amount to the seller) and add this to the protocol / referrers rewards\\n```\\n    function claimBids(uint96 lotId_, uint64[] calldata bidIds_) external override nonReentrant {\\n        \\n        // rest of code.\\n\\n        for (uint256 i = 0; i < bidClaimsLen; i++) {\\n            Auction.BidClaim memory bidClaim = bidClaims[i];\\n\\n            if (bidClaim.payout > 0) {\\n               \\n=>              _allocateQuoteFees(\\n                    protocolFee,\\n                    referrerFee,\\n                    bidClaim.referrer,\\n                    routing.seller,\\n                    routing.quoteToken,\\n=>                  bidClaim.paid\\n                );\\n```\\n\\nHere bidClaim.paid is the amount of quote tokens that was transferred in by the bidder for the purchase\\n```\\n    function _allocateQuoteFees(\\n        uint96 protocolFee_,\\n        uint96 referrerFee_,\\n        address referrer_,\\n        address seller_,\\n        ERC20 quoteToken_,\\n        uint96 amount_\\n    ) internal returns (uint96 totalFees) {\\n        // Calculate fees for purchase\\n        (uint96 toReferrer, uint96 toProtocol) = calculateQuoteFees(\\n            protocolFee_, referrerFee_, referrer_ != address(0) && referrer_ != seller_, amount_\\n        );\\n\\n        // Update fee balances if non-zero\\n        if (toReferrer > 0) rewards[referrer_][quoteToken_] += uint256(toReferrer);\\n        if (toProtocol > 0) rewards[_protocol][quoteToken_] += uint256(toProtocol);\\n\\n\\n        return toReferrer + toProtocol;\\n    }\\n```\\n\\nWhenever the seller calls claimProceeds to withdraw the amount of quote tokens received from the auction, subtract the quote fees and give out the remaining\\n```\\n    function claimProceeds(\\n        uint96 lotId_,\\n        bytes calldata callbackData_\\n    ) external override nonReentrant {\\n        \\n        // rest of code.\\n        \\n        uint96 totalInLessFees;\\n        {\\n=>          (, uint96 toProtocol) = calculateQuoteFees(\\n                lotFees[lotId_].protocolFee, lotFees[lotId_].referrerFee, false, purchased_\\n            );\\n            unchecked {\\n=>              totalInLessFees = purchased_ - toProtocol;\\n            }\\n        }\\n```\\n\\nHere purchased is the total quote token amount that was collected for this auction.\\nIn case the fees calculated in claimProceeds is less than the sum of fees allocated to the protocol / referrer via claimBids, there will be a mismatch causing the sum of (fees allocated + seller purchased quote tokens) to be greater than the total quote token amount that was transferred in for the auction. This could cause either the protocol/referrer to not obtain their rewards or the seller to not be able to claim the purchased tokens in case there are no excess quote token present in the auction house contract.\\nIn case, totalPurchased is >= sum of all individual bid quote token amounts (as it is supposed to be), the fee allocation would be correct. But due to the inaccurate computation of the input quote token amount associated with a partial fill, it is possible for the above scenario (ie. fees calculated in claimProceeds is less than the sum of fees allocated to the protocol / referrer via claimBids) to occur\\n```\\n    function settle(uint96 lotId_) external override nonReentrant {\\n        \\n        // rest of code.\\n\\n            if (settlement.pfBidder != address(0)) {\\n\\n                _allocateQuoteFees(\\n                    feeData.protocolFee,\\n                    feeData.referrerFee,\\n                    settlement.pfReferrer,\\n                    routing.seller,\\n                    routing.quoteToken,\\n\\n                    // @audit this method of calculating the input quote token amount associated with a partial fill is not accurate\\n                    uint96(\\n=>                      Math.mulDivDown(\\n                            settlement.pfPayout, settlement.totalIn, settlement.totalOut\\n                        )\\n                    )\\n```\\n\\nThe above method of calculating the input token amount associated with a partial fill can cause this value to be higher than the acutal value and hence the fees allocated will be less than what the fees that will be captured from the seller will be\\nPOC\\nApply the following diff to `test/AuctionHouse/AuctionHouseTest.sol` and run `forge test --mt testHash_SpecificPartialRounding -vv`\\nIt is asserted that the tokens allocated as fees is greater than the tokens that will be captured from a seller for fees\\n```\\ndiff --git a/moonraker/test/AuctionHouse/AuctionHouseTest.sol b/moonraker/test/AuctionHouse/AuctionHouseTest.sol\\nindex 44e717d..9b32834 100644\\n--- a/moonraker/test/AuctionHouse/AuctionHouseTest.sol\\n// Add the line below\\n// Add the line below\\n// Add the line below\\n b/moonraker/test/AuctionHouse/AuctionHouseTest.sol\\n@@ -6,6 // Add the line below\\n6,8 @@ import {Test} from "forge-std/Test.sol";\\n import {ERC20} from "solmate/tokens/ERC20.sol";\\n import {Transfer} from "src/lib/Transfer.sol";\\n import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";\\n// Add the line below\\nimport {SafeCastLib} from "solmate/utils/SafeCastLib.sol";\\n// Add the line below\\n\\n \\n // Mocks\\n import {MockAtomicAuctionModule} from "test/modules/Auction/MockAtomicAuctionModule.sol";\\n@@ -134,6 // Add the line below\\n136,158 @@ abstract contract AuctionHouseTest is Test, Permit2User {\\n         _bidder = vm.addr(_bidderKey);\\n     }\\n \\n// Add the line below\\n        function testHash_SpecificPartialRounding() public {\\n// Add the line below\\n        /*\\n// Add the line below\\n            capacity 1056499719758481066\\n// Add the line below\\n            previous total amount 1000000000000000000\\n// Add the line below\\n            bid amount 2999999999999999999997\\n// Add the line below\\n            price 2556460687578254783645\\n// Add the line below\\n            fullFill 1173497411705521567\\n// Add the line below\\n            excess 117388857750942341\\n// Add the line below\\n            pfPayout 1056108553954579226\\n// Add the line below\\n            pfRefund 300100000000000000633\\n// Add the line below\\n            new totalAmountIn 2700899999999999999364\\n// Add the line below\\n            usedContributionForQuoteFees 2699900000000000000698\\n// Add the line below\\n            quoteTokens1 1000000\\n// Add the line below\\n            quoteTokens2 2699900000\\n// Add the line below\\n            quoteTokensAllocated 2700899999\\n// Add the line below\\n        */\\n// Add the line below\\n\\n// Add the line below\\n        uint bidAmount = 2999999999999999999997;\\n// Add the line below\\n        uint marginalPrice = 2556460687578254783645;\\n// Add the line below\\n        uint capacity = 1056499719758481066;\\n// Add the line below\\n        uint previousTotalAmount = 1000000000000000000;\\n// Add the line below\\n        uint baseScale = 1e18;\\n// Add the line below\\n\\n// Add the line below\\n        // hasn't reached the capacity with previousTotalAmount\\n// Add the line below\\n        assert(\\n// Add the line below\\n            FixedPointMathLib.mulDivDown(previousTotalAmount, baseScale, marginalPrice) <\\n// Add the line below\\n                capacity\\n// Add the line below\\n        );\\n// Add the line below\\n\\n// Add the line below\\n        uint capacityExpended = FixedPointMathLib.mulDivDown(\\n// Add the line below\\n            previousTotalAmount // Add the line below\\n bidAmount,\\n// Add the line below\\n            baseScale,\\n// Add the line below\\n            marginalPrice\\n// Add the line below\\n        );\\n// Add the line below\\n        assert(capacityExpended > capacity);\\n// Add the line below\\n\\n// Add the line below\\n        uint totalAmountIn = previousTotalAmount // Add the line below\\n bidAmount;\\n// Add the line below\\n\\n// Add the line below\\n        uint256 fullFill = FixedPointMathLib.mulDivDown(\\n// Add the line below\\n            uint256(bidAmount),\\n// Add the line below\\n            baseScale,\\n// Add the line below\\n            marginalPrice\\n// Add the line below\\n        );\\n// Add the line below\\n\\n// Add the line below\\n        uint256 excess = capacityExpended - capacity;\\n// Add the line below\\n\\n// Add the line below\\n        uint pfPayout = SafeCastLib.safeCastTo96(fullFill - excess);\\n// Add the line below\\n        uint pfRefund = SafeCastLib.safeCastTo96(\\n// Add the line below\\n            FixedPointMathLib.mulDivDown(uint256(bidAmount), excess, fullFill)\\n// Add the line below\\n        );\\n// Add the line below\\n\\n// Add the line below\\n        totalAmountIn -= pfRefund;\\n// Add the line below\\n\\n// Add the line below\\n        uint usedContributionForQuoteFees;\\n// Add the line below\\n        {\\n// Add the line below\\n            uint totalOut = SafeCastLib.safeCastTo96(\\n// Add the line below\\n                capacityExpended > capacity ? capacity : capacityExpended\\n// Add the line below\\n            );\\n// Add the line below\\n\\n// Add the line below\\n            usedContributionForQuoteFees = FixedPointMathLib.mulDivDown(\\n// Add the line below\\n                pfPayout,\\n// Add the line below\\n                totalAmountIn,\\n// Add the line below\\n                totalOut\\n// Add the line below\\n            );\\n// Add the line below\\n        }\\n// Add the line below\\n\\n// Add the line below\\n        {\\n// Add the line below\\n            uint actualContribution = bidAmount - pfRefund;\\n// Add the line below\\n\\n// Add the line below\\n            // acutal contribution is less than the usedContributionForQuoteFees\\n// Add the line below\\n            assert(actualContribution < usedContributionForQuoteFees);\\n// Add the line below\\n            console2.log("actual contribution", actualContribution);\\n// Add the line below\\n            console2.log(\\n// Add the line below\\n                "used contribution for fees",\\n// Add the line below\\n                usedContributionForQuoteFees\\n// Add the line below\\n            );\\n// Add the line below\\n        }\\n// Add the line below\\n\\n// Add the line below\\n        // calculating quote fees allocation\\n// Add the line below\\n        // quote fees captured from the seller\\n// Add the line below\\n        {\\n// Add the line below\\n            (, uint96 quoteTokensAllocated) = calculateQuoteFees(\\n// Add the line below\\n                1e3,\\n// Add the line below\\n                0,\\n// Add the line below\\n                false,\\n// Add the line below\\n                SafeCastLib.safeCastTo96(totalAmountIn)\\n// Add the line below\\n            );\\n// Add the line below\\n\\n// Add the line below\\n            // quote tokens that will be allocated for the earlier bid\\n// Add the line below\\n            (, uint96 quoteTokens1) = calculateQuoteFees(\\n// Add the line below\\n                1e3,\\n// Add the line below\\n                0,\\n// Add the line below\\n                false,\\n// Add the line below\\n                SafeCastLib.safeCastTo96(previousTotalAmount)\\n// Add the line below\\n            );\\n// Add the line below\\n\\n// Add the line below\\n            // quote tokens that will be allocated for the partial fill\\n// Add the line below\\n            (, uint96 quoteTokens2) = calculateQuoteFees(\\n// Add the line below\\n                1e3,\\n// Add the line below\\n                0,\\n// Add the line below\\n                false,\\n// Add the line below\\n                SafeCastLib.safeCastTo96(usedContributionForQuoteFees)\\n// Add the line below\\n            );\\n// Add the line below\\n            \\n// Add the line below\\n            console2.log("quoteTokens1", quoteTokens1);\\n// Add the line below\\n            console2.log("quoteTokens2", quoteTokens2);\\n// Add the line below\\n            console2.log("quoteTokensAllocated", quoteTokensAllocated);\\n// Add the line below\\n\\n// Add the line below\\n            // quoteToken fees allocated is greater than what will be captured from seller\\n// Add the line below\\n            assert(quoteTokens1 // Add the line below\\n quoteTokens2 > quoteTokensAllocated);\\n// Add the line below\\n        }\\n// Add the line below\\n    }\\n// Add the line below\\n\\n// Add the line below\\n        function calculateQuoteFees(\\n// Add the line below\\n        uint96 protocolFee_,\\n// Add the line below\\n        uint96 referrerFee_,\\n// Add the line below\\n        bool hasReferrer_,\\n// Add the line below\\n        uint96 amount_\\n// Add the line below\\n    ) public pure returns (uint96 toReferrer, uint96 toProtocol) {\\n// Add the line below\\n        uint _FEE_DECIMALS = 5;\\n// Add the line below\\n        uint96 feeDecimals = uint96(_FEE_DECIMALS);\\n// Add the line below\\n\\n// Add the line below\\n        if (hasReferrer_) {\\n// Add the line below\\n            // In this case we need to:\\n// Add the line below\\n            // 1. Calculate referrer fee\\n// Add the line below\\n            // 2. Calculate protocol fee as the total expected fee amount minus the referrer fee\\n// Add the line below\\n            //    to avoid issues with rounding from separate fee calculations\\n// Add the line below\\n            toReferrer = uint96(\\n// Add the line below\\n                FixedPointMathLib.mulDivDown(amount_, referrerFee_, feeDecimals)\\n// Add the line below\\n            );\\n// Add the line below\\n            toProtocol =\\n// Add the line below\\n                uint96(\\n// Add the line below\\n                    FixedPointMathLib.mulDivDown(\\n// Add the line below\\n                        amount_,\\n// Add the line below\\n                        protocolFee_ // Add the line below\\n referrerFee_,\\n// Add the line below\\n                        feeDecimals\\n// Add the line below\\n                    )\\n// Add the line below\\n                ) -\\n// Add the line below\\n                toReferrer;\\n// Add the line below\\n        } else {\\n// Add the line below\\n            // If there is no referrer, the protocol gets the entire fee\\n// Add the line below\\n            toProtocol = uint96(\\n// Add the line below\\n                FixedPointMathLib.mulDivDown(\\n// Add the line below\\n                    amount_,\\n// Add the line below\\n                    protocolFee_ // Add the line below\\n referrerFee_,\\n// Add the line below\\n                    feeDecimals\\n// Add the line below\\n                )\\n// Add the line below\\n            );\\n// Add the line below\\n        }\\n// Add the line below\\n    }\\n// Add the line below\\n\\n// Add the line below\\n\\n     // ===== Helper Functions ===== //\\n \\n     function _mulDivUp(uint96 mul1_, uint96 mul2_, uint96 div_) internal pure returns (uint96) {\\n```\\n
Use `bidAmount - pfRefund` as the quote token input amount value instead of computing the current way
Rewards might not be collectible or seller might not be able to claim the proceeds due to lack of tokens
```\\n    function claimBids(uint96 lotId_, uint64[] calldata bidIds_) external override nonReentrant {\\n        \\n        // rest of code.\\n\\n        for (uint256 i = 0; i < bidClaimsLen; i++) {\\n            Auction.BidClaim memory bidClaim = bidClaims[i];\\n\\n            if (bidClaim.payout > 0) {\\n               \\n=>              _allocateQuoteFees(\\n                    protocolFee,\\n                    referrerFee,\\n                    bidClaim.referrer,\\n                    routing.seller,\\n                    routing.quoteToken,\\n=>                  bidClaim.paid\\n                );\\n```\\n