# Users can swap at the best price by splitting swap into several small swap

Bug Deep Dive #9 · 5 December 2025

Bug Deep Dives · [The Contest Academy](https://0xsimao.com/the-contest-academy) · 0xSimao

---

| Title | Users can swap at the best price by splitting swap into several small swap |
| Reward | $1633, 6 dups |
| Contest | Dango Dex - 15 Sep 2025 on Sherlock |
| Author | ami |
| Context | Business Logic |

**Alpha:** this is one of those findings that comes up when you ask what happens if the same function is called several times with smaller amounts. It applies to any kind of maths, not just swaps.

Here it is more of a business-logic issue than a rounding one, but the thought process that gets you there is the same.\
\
When swapping in a geometric pair, the protocol matches the passive orders against the user's swap order.\
However, users can swap at the best price by splitting one swap into several small ones.\
The `reflect_curve` function creates `params.limit` ask and bid orders.\
The bid prices decrease and the ask prices increase.\
By splitting the swap into several small swaps, a user can always take the best passive order.\
Consider the following scenario:

**Initial State**

Reserves of token1 and token2: 1000, 1000

1 token1 = 10 USD, 1 token2 = 1 USD

`swap_fee_rate` is 0, for simplicity

params.spacing: 1\
params.limit: 3\
params.ratio: 10%

**Path 1**

Alice is going to swap 300 token1 to token2 in one transaction:

The `reflect_curve` function creates 3 passive bids, as (price, size): (10, 100), (9, 111.11), (8, 125).

As a result, Alice receives **2712** token2:

$$100 \cdot 10 + 111.11 \cdot 9 + 89 \cdot 8 = 1000 + 1000 + 712 = 2712$$

**Path 2**

If Bob instead swaps 300 token1 as three swaps of 100 token1, in a single transaction:

Bob receives 1000 token2 for each swap of 100 token1, so **3000** token2 in total — more than Alice, for the same input.

**Conclusion**

This finding would earn you **\$1633**, and it is not hard to come up with. The explanation is not deep, but it does its job: always think like an attacker, and try splitting a transaction into smaller ones.

[**Full Report**](https://audits.sherlock.xyz/contests/1066/report)\
[**Codebase**](https://github.com/left-curve/left-curve/tree/main/dango/dex)

---

Newer: [Asymmetric liquidity provision to geometric pool can allow attacker to purchase at flat oracle price, irrespective of trade size](https://0xsimao.com/the-contest-academy/bug-deep-dive-10) · Older: [Incorrect rounding direction in geometric pool ask_exact_amount_out allows theft of funds](https://0xsimao.com/the-contest-academy/bug-deep-dive-8)
