# The _matcho() is not implemented properly

RubiconMarket._matcho passes m_pay_amt instead of m_pay_amt+fee to buy(), so partial matches revert when taker amount exceeds best offer.

- Payout: Contest reward
- Severity: medium
- Program: Rubicon
- Credited: KingNFT
- Disclosed: 2025-02-17
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-04-rubicon-findings/issues/1243
- Library page: https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-06
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** RubiconMarket.sol _matcho() order matching
**Root cause:** In _matcho(), buy() is called with min(m_pay_amt, t_buy_amt) but the maker's pay amount excludes the 0.01% fee, so the actual taken amount is 0.9999x and the subsequent accounting/transfer reverts when the taker's amount exceeds the best offer.
**Steps:**
1. Deploy RubiconMarket, set feeBPS=10 (0.01%).
2. Maker calls `market.offer(1e18, RUBI, 100e6, USDC)` selling 1 RUBI at 100 USDC.
3. Taker calls `market.offer(1000e6, USDC, 10e18, RUBI)` buying 10 RUBI at same price.
4. Observe partial take of 0.9999e18 RUBI (fee deducted) instead of 1e18, then revert on remaining match.
**How found:** Traced the emitTake log showing take_amt 0.9999e18 vs expected 1e18, identified the 0.01% fee discrepancy, then read _matcho L1313 where m_pay_amt is passed without adding fee.
**Insight:** When auditing order-matching loops, compare emitted take amounts against expected amounts to spot fee-inclusive vs fee-exclusive accounting mismatches that break partial fills.
