Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 95 additions & 1 deletion config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
[bot]
# Drop opportunities below this USD profit threshold, in USD × 1e6.
# 5_000_000 = $5.00. Integer fixed-point to avoid f64 precision.
min_profit_usd_1e6 = 5000000
# Set to 0 to disable the absolute-USD floor — the margin gate
# (`min_profit_margin_bps`) below is the primary drop reason now.
min_profit_usd_1e6 = 0
# Required margin on TOTAL COST (flash fee + gas + slippage), in bps.
# 1_000 = 10% margin: the swap output must return at least
# 1.10 × total_cost. If total cost is 100 units of debt token, the
# pipeline rejects anything that would return less than 110.
# Set to 0 to disable the margin gate (USD floor still applies).
min_profit_margin_bps = 1000
# Skip liquidations when gas price exceeds this, in wei (decimal string).
# "3000000000" = 3 gwei. Sub-gwei priority fees are representable.
max_gas_wei = "3000000000"
Expand Down Expand Up @@ -62,13 +70,76 @@ chunk_max_attempts = 4
chunk_initial_backoff_ms = 500
chunk_max_backoff_ms = 5000

# Ethereum mainnet — added via the multi-chain abstraction (#…). The
# bot's runtime pipeline is still Venus-on-BSC by default; declaring
# the chain here lets the per-protocol scanner loop pick up Aave V3 on
# Ethereum once the CLI iterates `[protocol.*]` rather than the
# hardcoded `[protocol.venus]` lookup. Until then the section is
# parsed and validated but inert at runtime.
[chain.eth]
chain_id = 1
ws_url = "${ETH_WS_URL}"
http_url = "${ETH_HTTP_URL}"
# Mainnet base fee floor + a small tip; raise during congestion.
priority_fee_gwei = 1
# Same private-mempool gate as BSC: every chain must carry a
# `private_rpc_url` or explicitly opt in to the public mempool.
# Flashbots / MEV-Share is the canonical choice here.
private_rpc_url = "${CHARON_ETH_PRIVATE_RPC_URL}"
private_rpc_auth = "${CHARON_ETH_PRIVATE_RPC_AUTH}"
allow_public_mempool = false

[chain.eth.discovery]
# 7 days @ ~12s blocks ≈ 50_400 blocks. Free-tier RPCs cap chunks
# tighter than BSC; widen on a paid archive endpoint.
backfill_blocks = 50000
log_chunk_blocks = 5000
inter_chunk_pacing_ms = 50
chunk_max_attempts = 4
chunk_initial_backoff_ms = 500
chunk_max_backoff_ms = 5000

# ── Lending protocols ─────────────────────────────────────────────────────
[protocol.venus]
chain = "bnb"
# Compound-family adapter family. `kind` defaults to "venus" so this
# field is optional; declared explicitly here for symmetry with the
# Aave V3 entry below.
kind = "venus"
# Venus Unitroller (main comptroller on BSC)
comptroller = "0xfd36e2c2a6789db23113685031d7f16329158384"

# Aave V3 on Ethereum mainnet. Wired in via the new `kind = "aave_v3"`
# discriminator on `[protocol.*]` (see `ProtocolKind` in
# charon-core::config). Addresses from Aave's address book — verify at
# <https://aave.com/docs/resources/addresses> before depending on
# this for live broadcasts.
[protocol.aave_v3_eth]
chain = "eth"
kind = "aave_v3"
# Aave V3 Pool on Ethereum mainnet (entry point for liquidationCall).
pool = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
# Optional: IPoolAddressesProvider — when set the CLI will compare
# `getPool() == pool` at startup, mirroring the existing flash-loan
# section's belt-and-braces gate (#367). Mainnet provider:
pool_addresses_provider = "0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e"
# AaveOracle — USD-1e8 prices for every reserve asset.
oracle = "0x54586bE62E3c3580375aE3723C145253060Ca0C2"
# PoolDataProvider — per-asset reserve config (decimals, liquidation
# bonus) and per-user reserve breakdown. v3.1 deployment:
data_provider = "0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3"

# ── Flash-loan sources ────────────────────────────────────────────────────
[flashloan.aave_v3_eth]
chain = "eth"
# Aave V3 Pool on Ethereum mainnet (the same Pool address used by the
# `[protocol.aave_v3_eth]` section above — Aave V3 lets borrowers
# liquidate via the same contract that exposes flashLoanSimple, so
# the flash-loan source and the lending protocol share an address).
pool = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
data_provider = "0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3"
addresses_provider = "0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e"

[flashloan.aave_v3_bsc]
chain = "bnb"
# Aave V3 Pool on BSC (used for flashLoanSimple — 0.05% fee)
Expand Down Expand Up @@ -132,6 +203,20 @@ ETH = "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e"
USDT = "0xB97Ad0E74fa7d920791E90258A6E2085088b4320"
USDC = "0x51597f405303C4377E36123cBc172b13269EA163"

# Ethereum mainnet Chainlink feeds. Symbols are matched against the
# token symbols resolved at runtime by `TokenMetaCache::build` from
# each underlying ERC-20's `symbol()`. WETH's `symbol()` returns
# `"WETH"`, so the `WETH` key below is what the profit gate asks
# for; the `ETH` key is included separately as the **native gas
# token** symbol for `native_feed_symbol_for_chain("eth")`.
[chainlink.eth]
ETH = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" # ETH / USD — native feed
WETH = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419" # same aggregator as ETH
USDT = "0x3E7d1eAB13ad0104d2750B8863b489D65364e32D"
USDC = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"
DAI = "0xAed0c38402a5d19dF6E4c03F4E2DceD6e29c1ee9"
WBTC = "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c" # BTC / USD aggregator (WBTC tracks BTC)

# Per-feed staleness windows (seconds). Stable-coin Chainlink feeds on
# BSC update on deviation, not heartbeat — the global 600s default
# routinely flags USDT / USDC / FDUSD as stale even when the price has
Expand All @@ -141,3 +226,12 @@ USDC = "0x51597f405303C4377E36123cBc172b13269EA163"
[chainlink_max_age_secs.bnb]
USDT = 86400
USDC = 86400

# Same stable-feed widening as BSC. Ethereum stable Chainlink feeds
# also update on deviation rather than heartbeat, so the global
# default of 600s flags them as stale even when the price hasn't
# moved.
[chainlink_max_age_secs.eth]
USDT = 86400
USDC = 86400
DAI = 86400
95 changes: 95 additions & 0 deletions config/fork-eth.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Charon — local anvil fork profile (Ethereum mainnet state, local host).
#
# Pair with `scripts/anvil_fork_eth.sh` (or any anvil --fork-url …
# command pointed at an Eth archive RPC). The fork process exposes
# HTTP+WS on 127.0.0.1:${CHARON_ANVIL_PORT:-8545} and mirrors every
# mainnet address the default profile uses for `[chain.eth]` /
# `[protocol.aave_v3_eth]` / `[flashloan.aave_v3_eth]`.
#
# Why a separate file from `fork.toml`:
# - Different chain (eth vs bnb), different protocol (Aave V3 vs Venus).
# - Different deterministic CharonLiquidator constructor args (Aave V3
# Pool / Uniswap V3 SwapRouter on Ethereum, not the BSC equivalents).
#
# Running a secondary fork on a different port:
# CHARON_ANVIL_PORT=8546 ./scripts/anvil_fork_eth.sh
# CHARON_ANVIL_PORT=8546 charon --config config/fork-eth.toml replay …

[bot]
# Lower gate for demo staging (mirrors fork.toml).
min_profit_usd_1e6 = 0
min_profit_margin_bps = 100
# 5_000 gwei. Aug 5 2024 cascade hit ~1280 gwei base fee — widen
# generously so historical-volatility demo blocks (USDC depeg, FTX,
# yen unwind) clear the gas gate.
max_gas_wei = "5000000000000"
scan_interval_ms = 1000
signer_key = "${CHARON_SIGNER_KEY:-}"
profile_tag = "fork"

# ── Chains ────────────────────────────────────────────────────────────────
[chain.eth]
chain_id = 1
ws_url = "ws://127.0.0.1:${CHARON_ANVIL_PORT:-8545}"
http_url = "http://127.0.0.1:${CHARON_ANVIL_PORT:-8545}"
priority_fee_gwei = 1

[chain.eth.discovery]
backfill_blocks = 50000
log_chunk_blocks = 100000
inter_chunk_pacing_ms = 0
chunk_max_attempts = 4
chunk_initial_backoff_ms = 500
chunk_max_backoff_ms = 5000

# ── Lending protocols ─────────────────────────────────────────────────────
[protocol.aave_v3_eth]
chain = "eth"
kind = "aave_v3"
pool = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
pool_addresses_provider = "0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e"
oracle = "0x54586bE62E3c3580375aE3723C145253060Ca0C2"
data_provider = "0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3"

# ── Flash-loan sources ────────────────────────────────────────────────────
[flashloan.aave_v3_eth]
chain = "eth"
pool = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
data_provider = "0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3"
addresses_provider = "0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e"

# ── Prometheus metrics exporter ───────────────────────────────────────────
[metrics]
enabled = true
bind = "127.0.0.1:9091"

# ── Chainlink price feeds (Ethereum mainnet) ──────────────────────────────
[chainlink.eth]
ETH = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"
WETH = "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"
USDT = "0x3E7d1eAB13ad0104d2750B8863b489D65364e32D"
USDC = "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"
DAI = "0xAed0c38402a5d19dF6E4c03F4E2DceD6e29c1ee9"
WBTC = "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c"

# Pinned anvil at a block from a year ago (Aug 2024 demo) reads
# Chainlink rounds whose `updatedAt` is ~640 days behind wall clock.
# The staleness check compares against `now()` not `block.timestamp`,
# so widen aggressively for the demo. 2 years = 63072000 seconds.
[chainlink_max_age_secs.eth]
USDT = 63072000
USDC = 63072000
DAI = 63072000
ETH = 63072000
WETH = 63072000
WBTC = 63072000

# ── Deployed liquidator (deterministic anvil dev-0 address) ──────────────
# Same address as fork.toml's [liquidator.bnb] — comes from
# `forge create` against anvil dev-account 0
# (0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266) at nonce 0.
# `scripts/anvil_fork.sh` resets the dev-0 nonce + wipes the deploy
# slot, so the first `forge create` in this profile lands here too.
[liquidator.eth]
chain = "eth"
contract_address = "0x5FbDB2315678afecb367f032d93F642f64180aa3"
10 changes: 8 additions & 2 deletions config/fork.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@

[bot]
# Lower gate for demo staging — real ops should use default.toml.
# $0.01 in USD × 1e6 fixed-point (post feat/19 integer schema).
min_profit_usd_1e6 = 10000
# USD floor disabled (margin gate below is primary). 10_000 = $0.01
# was the pre-margin-gate sentinel — keep at 0 here so the 110%
# margin gate alone decides demo passes.
min_profit_usd_1e6 = 0
# Looser margin for demo: 1% on total cost (default profile uses 10%).
# Synthetic / partial positions on a fork rarely clear a 10% margin,
# and the fork is not where a thin-margin liquidation costs anything.
min_profit_margin_bps = 100
# 20 gwei, expressed in wei (decimal string). Matches the lowered
# demo-gate intent: cheap anvil transactions shouldn't get filtered.
max_gas_wei = "20000000000"
Expand Down
8 changes: 6 additions & 2 deletions config/testnet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@

[bot]
# Low threshold so any testnet-scale opportunity can cross the gate.
# 10_000 = $0.01 in fixed-point (USD × 1e6).
min_profit_usd_1e6 = 10000
# USD floor disabled (margin gate primary). Pre-margin-gate value was
# 10_000 = $0.01.
min_profit_usd_1e6 = 0
# Margin-gate primary; keep loose on testnet (1%) so synthetic
# positions on Chapel clear without manual tuning.
min_profit_margin_bps = 100
# 20 gwei ceiling, expressed in wei. Generous for Chapel where traffic
# is light; mirrors mainnet units so the same knob works everywhere.
max_gas_wei = "20000000000"
Expand Down
Loading
Loading