feat(cli): real per-token USD pricing + real gas cost in profit gate#306
Merged
feat(cli): real per-token USD pricing + real gas cost in profit gate#306
Conversation
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).
# Conflicts: # crates/charon-cli/src/main.rs # crates/charon-scanner/src/lib.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 }+TokenMetaCachewrappingHashMap<Address, TokenMeta>.TokenMetaCache::build(provider, tokens)queriesERC20::symbol()+decimals()once at startup. Best-effort: failing tokens log aterror!with "market is now UNREACHABLE by the profit gate" and are skipped.crates/charon-cli/src/main.rsPLACEHOLDER_GAS_USD_CENTS+repay_to_usd_cents_placeholder.run_listenalways constructsGasOracle, buildsTokenMetaCachefromadapter.underlying_to_vtoken.keys(), bails iftoken_meta.is_empty()orNATIVE_FEED_SYMBOL = "BNB"missing from Chainlink.process_blockfetches onegas_snapshot(Option) per tick (singleget_blockshared across every opp).process_opportunitydrops on: unknown debt meta, missing/stale debt price, missing/stale BNB price, or no gas snapshot.amount_to_usd_cents(amount, token_dec, price, price_dec)using saturating U256 math.PROFIT_GATE_ROUGH_GAS_UNITS = 1_500_000,NATIVE_FEED_SYMBOL = "BNB".Review
blockchain-code-reviewer: request-changes -> appliederror!with explicit unreachable-market wording.TokenMetaCacheat startup.Test plan
cargo build --workspacecleancargo clippy -p charon-cli -p charon-scanner -- -D warningsclean--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.