Refs #39
File: crates/charon-core/src/flashloan.rs — FlashLoanProvider trait
Problem
All FlashLoanProvider methods return anyhow::Result. The router's cheapest-first walk must distinguish:
- InsufficientLiquidity: try next provider
- ReservePaused/Frozen: skip this provider for this asset
- RPC transport error: abort entirely, do not fall through to a cheaper-looking provider
With anyhow::Error these cases require string-matching on error messages, which is brittle and untestable. The same mistake exists on LendingProtocol (flagged in PR #28) and has not been fixed. Extending it to a second public trait compounds the debt.
Impact: Any RPC error on provider A is silently swallowed and triggers fallback to provider B. The bot may execute at a higher cost or against a wrong provider when a transient RPC failure occurs.
Fix
Define in crates/charon-core/src/flashloan.rs:
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FlashLoanError {
#[error("insufficient liquidity: available {available}, requested {requested}")]
InsufficientLiquidity { available: U256, requested: U256 },
#[error("reserve paused or frozen for asset {asset}")]
ReservePaused { asset: Address },
#[error("rpc error: {0}")]
Rpc(#[from] alloy::transports::TransportError),
#[error("{0}")]
Other(#[from] anyhow::Error),
}
Change all trait method signatures to Result<T, FlashLoanError>. thiserror is already a transitive dependency via charon-protocols.
Refs #39
File: crates/charon-core/src/flashloan.rs — FlashLoanProvider trait
Problem
All FlashLoanProvider methods return anyhow::Result. The router's cheapest-first walk must distinguish:
With anyhow::Error these cases require string-matching on error messages, which is brittle and untestable. The same mistake exists on LendingProtocol (flagged in PR #28) and has not been fixed. Extending it to a second public trait compounds the debt.
Impact: Any RPC error on provider A is silently swallowed and triggers fallback to provider B. The bot may execute at a higher cost or against a wrong provider when a transient RPC failure occurs.
Fix
Define in crates/charon-core/src/flashloan.rs:
Change all trait method signatures to Result<T, FlashLoanError>. thiserror is already a transitive dependency via charon-protocols.