Skip to content

[flashloan] FlashLoanProvider trait returns anyhow::Error — router cannot distinguish no-liquidity from RPC failure #141

@obchain

Description

@obchain

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.

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