# Logical error in validate_fees_are_paid can cause a DoS or allow users to bypass fees if denom_creation_fee includes multiple coins, including pool_creation_fee, and the user attempts to pay all fees using only pool_creation_fee

Fee validation in MANTRA pool-manager double-counts a single payment across pool_creation_fee and denom_creation_fee, enabling fee bypass or DoS.

- Payout: Audit contest
- Severity: high
- Program: MANTRA
- Credited: 0xRajkumar
- Disclosed: 2025-03-31
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2024-11-mantra-dex#h-02
- Library page: https://bugbountylibrary.com/r/c4%3A2024-11-mantra-dex%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:fee-bypass

**Target:** CosmWasm pool-manager contract fee validation (helpers.rs)
**Root cause:** validate_fees_are_paid checks each fee independently against the same info.funds without tracking which coins were already consumed, so one payment satisfies both pool_creation_fee and denom_creation_fee when amounts match.
**Steps:**
1. Configure denom_creation_fee to include the same denom as pool_creation_fee with equal amount.
2. Call create pool sending only that single coin amount once.
3. Observe paid_pool_fee_amount == pool_creation_fee.amount passes.
4. Observe denom_creation_fee.iter().any(...) also passes on the same funds, bypassing one fee.
5. With differing amounts, sending the summed amount fails both equality checks, causing DoS.
**How found:** Code review of validate_fees_are_paid noticed both checks independently sum info.funds per denom without excluding already-accounted coins, and reasoned about equal vs differing fee amounts.
**Exploitation:** Attacker submits a pool creation tx paying only one fee amount; both fee checks read the same info.funds entry and pass, so the second fee is never actually paid.
**Insight:** When multiple required fees are validated against the same msg funds, check whether each coin is consumed once; equal-amount configs silently pass double-spend-of-payment checks.
