PR: #28 (feat/03-lending-protocol-trait)
File: crates/charon-core/src/traits.rs, lines 20-48
All three methods return anyhow::Result<T>. anyhow::Error is a type-erased bag — callers cannot match on variants to decide retry vs abort vs skip. Scanner needs to distinguish:
- transient RPC error → retry
- invalid position (decimals mismatch) → skip + log
- protocol state invariant broken (vToken address mismatch) → alert + halt
Impact: Scanner and executor cannot implement correct recovery logic. Every error forces full restart or blind retry. Downstream metrics layer cannot categorize failures.
Fix: Define LendingProtocolError with thiserror:
#[derive(Debug, thiserror::Error)]
pub enum LendingProtocolError {
#[error("RPC error: {0}")]
Rpc(#[source] alloy::transports::TransportError),
#[error("invalid position: {0}")]
InvalidPosition(String),
#[error("unsupported asset: {0}")]
UnsupportedAsset(Address),
#[error("protocol state: {0}")]
ProtocolState(String),
}
pub type Result<T> = std::result::Result<T, LendingProtocolError>;
Switch trait to return Result<T>.
PR: #28 (feat/03-lending-protocol-trait)
File: crates/charon-core/src/traits.rs, lines 20-48
All three methods return
anyhow::Result<T>.anyhow::Erroris a type-erased bag — callers cannot match on variants to decide retry vs abort vs skip. Scanner needs to distinguish:Impact: Scanner and executor cannot implement correct recovery logic. Every error forces full restart or blind retry. Downstream metrics layer cannot categorize failures.
Fix: Define
LendingProtocolErrorwiththiserror:Switch trait to return
Result<T>.