# RubiconRouter _swap does not pass whole amount to RubiconMarket

RubiconRouter._swap computes the sell amount with a wrong fee formula, leaving dust of user funds unforwarded to RubiconMarket on multi-pair swaps.

- Payout: Contest reward
- Severity: high
- Program: Rubicon
- Credited: kenzo
- Disclosed: 2022-08-01
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-05-rubicon-findings/issues/104
- Library page: https://bugbountylibrary.com/r/c4%3A2022-05-rubicon%3AH-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:fee-bypass

**Target:** RubiconRouter smart contract _swap / sellAllAmount
**Root cause:** The amount passed to sellAllAmount subtracts fee as amount*(1 - feeBPS/10000), but the market charges fee on the passed amount, so the gross should be amount*10000/(10000+feeBPS).
**Steps:**
1. Call RubiconRouter._swap across multiple pairs with expectedMarketFeeBPS=100
2. Observe currentAmount.sub(currentAmount.mul(100).div(10000)) = 99% of amount passed to sellAllAmount
3. Market charges 1% of 99 = 0.99, total used 99.99, leaving 0.01 dust unforwarded
4. Correct formula: currentAmount.sub(currentAmount.mul(feeBPS).div(10000+feeBPS))
**How found:** Code review of the fee accounting in _swap; noticed the fee was subtracted from the gross rather than grossing up the net, then proved the residual dust mathematically.
**Insight:** When a downstream contract charges a fee on the amount you pass it, invert the fee (gross = net*10000/(10000+feeBPS)) rather than subtracting a percentage of the gross; otherwise dust is stranded per swap.
