Skip to content

feat(cli): real per-token USD pricing + real gas cost in profit gate#306

Merged
obchain merged 2 commits intomainfrom
feat/real-profit-pricing
Apr 24, 2026
Merged

feat(cli): real per-token USD pricing + real gas cost in profit gate#306
obchain merged 2 commits intomainfrom
feat/real-profit-pricing

Conversation

@obchain
Copy link
Copy Markdown
Owner

@obchain obchain commented Apr 23, 2026

Summary

Replaces the two placeholders mev-sim-auditor flagged as a P1 econ blocker on PR #305:

  • repay_to_usd_cents_placeholder (every token as 18-dec $1)
  • PLACEHOLDER_GAS_USD_CENTS = 50 (flat 50c)

For BTCB / ETH / BNB debt the gate previously underpriced repayments by ~10^4 and overpriced-by-omission gas, so unprofitable txs would pass. This PR replaces both with real Chainlink-backed USD math.

Stacking

Base: feat/wire-submitter-cli (PR #305). Merges after #303, #304, #305.

Key changes

crates/charon-scanner/src/token_meta.rs (NEW)

  • TokenMeta { symbol, decimals } + TokenMetaCache wrapping HashMap<Address, TokenMeta>.
  • TokenMetaCache::build(provider, tokens) queries ERC20::symbol() + decimals() once at startup. Best-effort: failing tokens log at error! with "market is now UNREACHABLE by the profit gate" and are skipped.
  • 2 unit tests.

crates/charon-cli/src/main.rs

  • Removed PLACEHOLDER_GAS_USD_CENTS + repay_to_usd_cents_placeholder.
  • run_listen always constructs GasOracle, builds TokenMetaCache from adapter.underlying_to_vtoken.keys(), bails if token_meta.is_empty() or NATIVE_FEED_SYMBOL = "BNB" missing from Chainlink.
  • process_block fetches one gas_snapshot (Option) per tick (single get_block shared across every opp).
  • process_opportunity drops on: unknown debt meta, missing/stale debt price, missing/stale BNB price, or no gas snapshot.
  • New amount_to_usd_cents(amount, token_dec, price, price_dec) using saturating U256 math.
  • New constants: PROFIT_GATE_ROUGH_GAS_UNITS = 1_500_000, NATIVE_FEED_SYMBOL = "BNB".

Review

blockchain-code-reviewer: request-changes -> applied

  • Raised metadata failure log to error! with explicit unreachable-market wording.
  • Bail on empty TokenMetaCache at startup.

Test plan

  • cargo build --workspace clean
  • cargo clippy -p charon-cli -p charon-scanner -- -D warnings clean
  • All unit tests: core 24, executor 19, scanner 9 (2 new token_meta), cli 4 (new amount_to_usd_cents)
  • Fork-level replay — carried over from PR feat(cli): wire submitter into process_opportunity behind --execute #305 footnote; enables after Submitter scheme-gate decision + cold-wallet port

--execute status

Still OFF by default. With this PR merged, the profit gate is trustworthy for non-stablecoin debt. Remaining gate to live enablement is fork-level validation tracked under PR #305.

Replaces the two placeholders mev-sim-auditor flagged as a P1 econ
blocker on PR #305: `repay_to_usd_cents_placeholder` (treated every
token as 18-dec $1) and `PLACEHOLDER_GAS_USD_CENTS = 50` (flat 50c).
Before this change, for BTCB / ETH / BNB debt the profit gate
underpriced repayments by ~10^4 and overpriced-by-omission gas — so
the gate would pass unprofitable txs and the signer would bleed gas
under --execute.

Changes:

- New `charon-scanner::token_meta::TokenMetaCache`. Populated once at
  startup with `(symbol, decimals)` for every Venus underlying via
  `ERC20::symbol()` + `decimals()`. Tokens whose metadata calls fail
  log at `error!` and are skipped — the profit gate treats "no meta"
  the same as "no price" and drops. Bot refuses to start if the cache
  ends up empty (RPC or adapter wiring is broken).
- `run_listen` always constructs a `GasOracle` (no longer
  --execute-only) and also bails if the BNB/USD Chainlink feed is
  missing from the price cache — a missing native feed means gas cost
  cannot be priced in USD.
- `process_block` fetches one `gas_snapshot` (Option<GasParams>) per
  tick via the gas oracle, shared across every opportunity in that
  block so there is no fan-out of `get_block` calls.
- `process_opportunity` now takes `&PriceCache`, `&TokenMetaCache`,
  `Option<GasParams>`. Drops the opportunity if any of: unknown debt
  token meta, missing-or-stale Chainlink price for the debt token,
  missing-or-stale BNB/USD price, or gas snapshot unavailable.
- New `amount_to_usd_cents(amount, token_dec, price, price_dec) -> u64`
  using saturating U256 math, with 4 unit tests (USDT@$1, BTCB@$60k,
  zero price, overflow saturation).
- New constants `PROFIT_GATE_ROUGH_GAS_UNITS = 1_500_000` (Venus+Aave
  path empirical upper bound) and `NATIVE_FEED_SYMBOL = "BNB"`.

--execute remains OFF by default. With this PR plus #305 the profit
gate is now trustworthy for non-stablecoin debt; the next step before
enabling --execute on mainnet is a fork-level replay (deferred in
PR #305 pending Submitter scheme-gate decision and the cold-wallet
port from the sibling branch).
@obchain obchain changed the base branch from feat/wire-submitter-cli to main April 24, 2026 20:00
# Conflicts:
#	crates/charon-cli/src/main.rs
#	crates/charon-scanner/src/lib.rs
@obchain obchain merged commit 3ccb684 into main Apr 24, 2026
2 of 3 checks passed
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.

1 participant