Skip to content

[flashloan] fee_rate_bps semantic unit mismatch breaks router comparison across providers #136

@obchain

Description

@obchain

Refs #39

File: crates/charon-flashloan/src/aave.rs, crates/charon-flashloan/src/router.rs, crates/charon-core/src/flashloan.rs

Problem

Aave V3 FLASHLOAN_PREMIUM_TOTAL is in 4-decimal units where 5 means 0.05% (5 / 10_000). The adapter stores the raw value 5 in FlashLoanQuote.fee_rate_bps. The field name implies standard basis points (1 bp = 0.01%), so any caller interprets 5 as 0.05 bps — not 0.05%.

SwapRoute.pool_fee in types.rs uses 1/1_000_000 units (500 = 0.05%, 3000 = 0.3%). When the router gains a Uniswap V3 adapter that places its pool fee in fee_rate_bps using the same 1e6 convention, the router will compare Aave 5 against Uniswap 500 and always rank Uniswap as 100x more expensive, even when both cost 0.05%. A 0.3% Uniswap pool (fee_rate_bps = 3000) will be judged cheaper than an actual 0.3% Aave premium if Aave raises its fee to the equivalent of 30 in 4-decimal units.

This is a silent profit miscalculation embedded in the public trait interface. Fixing the units after adapters are downstream is a breaking API change.

Impact: Router selects the wrong (more expensive) flash-loan source in every multi-provider scenario, reducing net profit on every liquidation.

Fix

Normalize to a single canonical unit across all adapters. Recommend 1/1_000_000 (same as Uniswap pool_fee). Aave 0.05% premium becomes 500. Document the unit as an invariant on the FlashLoanProvider trait doc comment. Consider renaming the field to fee_rate_millionths to eliminate ambiguity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglayer:rustRust crates (core / scanner / protocols / executor / cli)priority:p1-coreCore MVP scope

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions