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.
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.