Skip to content

feat(core): add LendingProtocol async trait#28

Merged
obchain merged 2 commits intomainfrom
feat/03-lending-protocol-trait
Apr 24, 2026
Merged

feat(core): add LendingProtocol async trait#28
obchain merged 2 commits intomainfrom
feat/03-lending-protocol-trait

Conversation

@obchain
Copy link
Copy Markdown
Owner

@obchain obchain commented Apr 21, 2026

Closes #4

Defines the main async trait every protocol adapter (Venus, Aave, Compound, Morpho, …) implements. Scanner + executor consume it as trait objects — adding a new protocol stays self-contained.

Surface:

  • id() — stable protocol identifier
  • fetch_positions(borrowers) — async batch position lookup
  • get_liquidation_params(position) — protocol-specific params
  • build_liquidation_calldata(params) — ABI-encoded inner call

Uses async-trait to keep Box<dyn LendingProtocol> possible.

Extends LiquidationParams enum with the Venus variant carrying vToken addresses and repay amount.

Depends on #3 (feat/02-core-types).

…builders

Define the main protocol-adapter boundary: scanner and executor consume
LendingProtocol without caring which lending protocol is behind it.

Trait methods:
  - id(): returns the ProtocolId variant
  - fetch_positions(borrowers): async query of on-chain position state
  - get_liquidation_params(position): protocol-specific params (close
    factor, vToken addresses, etc.)
  - build_liquidation_calldata(params): ABI-encodes the
    CharonLiquidator.executeLiquidation call

Also add LiquidationParams enum to types (Venus variant only for v1) --
each protocol variant carries exactly the fields it needs rather than
a shared bag of options.

Uses async-trait to keep the trait dyn-compatible for
Box<dyn LendingProtocol> registries.
…/close/incentive queries

- Replace anyhow::Result on every trait method with Result<T, LendingProtocolError>.
  Variants (Rpc / InvalidPosition / UnsupportedAsset / ProtocolState / Abi)
  let callers match on failure mode — retry transient RPC errors, skip bad
  positions, escalate state-invariant breaks. Variant enum is #[non_exhaustive].
- fetch_positions takes BlockNumberOrTag for snapshot consistency. Scanner
  pins reads to the block it just observed; mempool monitor can pass Pending.
- Add get_health_factor(borrower, block) — single-account HF probe for
  mempool-driven refreshes, cheaper than fetch_positions for gating.
- Add get_close_factor(market) — required by profit calculator to bound
  repay_amount; Venus close factor is per-market and governed.
- Add get_liquidation_incentive(collateral_market) — per-market on Venus
  (liquidationIncentiveMantissa). Profit calculator scales seized
  collateral by this; hardcoding is wrong.
- LiquidationParams: add #[non_exhaustive] at enum and variant level so
  new protocols and new per-variant fields do not break downstream
  exhaustive matches.
- Keep #[async_trait]: Arc<dyn LendingProtocol> requires object safety,
  which native AFIT cannot provide without trait_variant bounds. Box-per-call
  overhead is negligible relative to RPC round-trips.
- Add workspace thiserror = "2"; wire into charon-core.

Closes #70 #71 #72 #73 #74
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[core] LendingProtocol async trait

1 participant