From c104b6015d2749eab92fc2fa1ab8ed777a42e5e3 Mon Sep 17 00:00:00 2001 From: obchain Date: Tue, 21 Apr 2026 17:27:43 +0530 Subject: [PATCH 1/2] chore: add README, MIT license, and .gitignore --- .gitignore | 22 +++++ CLAUDE.md | 78 +++++++++++++++ LICENSE | 21 ++++ README.md | 276 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1381a72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Rust build artifacts +/target/ +**/*.rs.bk + +# Environment / secrets +.env +.env.local + +# macOS +.DS_Store + +# Editor +.idea/ +.vscode/ + +# Logs +*.log + +# Local-only dev notes and editor configs +.claude/ +docs/context.md +NOTES.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..6a44798 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,78 @@ +# CLAUDE.md + +Global rules for any assistant (Claude Code or otherwise) working in +this repository. Humans contributing through a PR review get the same +rules by convention — but these are hard constraints for automated +tools. + +--- + +## Commits + +- NEVER add a `Co-Authored-By` line. +- Author + committer must be the human operator of the repo; never + an assistant, bot, or pair-programming identity. +- Commit messages describe the technical change only. No references + to AI tools, prompts, models, or this file. +- Follow Conventional Commits. Prefixes in use: `feat()`, + `fix()`, `chore`, `docs`, `test`, `refactor`, `perf`. + Subject ≤ 70 chars, imperative mood, lowercase. +- No emoji in subjects unless a PR template explicitly calls for it. + +## Branches and PRs + +- `main` is protected. **Never push directly to main.** Every change + lands via a pull request. +- One branch per GitHub issue: `feat/-`, `fix/-`, + `chore/-`. +- PR title mirrors the squash-merge subject. PR body must include + `Closes #` (or `Refs #` for partial progress) so the issue + tracker stays in sync. +- Squash-merge on acceptance. One commit per PR on `main`. +- PR descriptions: technical only. Same rule as commit messages — no + AI references. + +## Issues + +- Issue titles use a `[layer] subject` prefix, e.g. + `[scanner] Chainlink PriceCache staleness check`. +- Every issue carries `type:*`, `layer:*`, `priority:*`, `status:*` + labels and a milestone. +- Issue comments and closures: technical only, no AI references. + +## Workflow + +- Before any commit: run the gates locally. + - Rust: `cargo fmt --all`, `cargo clippy --workspace --all-targets + --all-features -- -D warnings`, `cargo test --workspace`. + - Solidity (Foundry, inside `contracts/`): + `forge build`, `forge fmt --check`, `forge test`. +- A pre-commit hook (local, not tracked) enforces the Rust gates on + any assistant-driven commit. Do not bypass with `--no-verify`. + +## Scope (v0.1) + +- **Venus protocol on BNB Chain only.** Multi-chain / multi-protocol + expansion is a config change later, not a rewrite. +- Secrets (`.env`, private keys, API tokens) **never** go into the + repo. Use `${ENV_VAR}` substitution in `config/default.toml`. + +## Safety invariants + +- The bot hot wallet holds gas only. Profit is swept to the cold + wallet inside every flash-loan callback. Do not introduce code that + parks profit in the hot wallet. +- Every liquidation transaction passes an `eth_call` simulation gate + before broadcast. Do not add a bypass. +- `CharonLiquidator.executeLiquidation` is `onlyOwner`. Do not weaken + or remove the modifier. +- Flash-loan atomicity is the last line of defense, not the first. + Off-chain gates (health factor, price freshness, profitability, gas + ceiling, flash-loan liquidity) must all run before simulation. + +## What not to track + +- Build artifacts (`target/`, `contracts/out/`, `contracts/cache/`). +- Editor configs (`.idea/`, `.vscode/`). +- Local-only notes and dev collaboration files. +- Anything containing secrets. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9d1ae44 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Charon Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..aafddfe --- /dev/null +++ b/README.md @@ -0,0 +1,276 @@ +# Charon + +> Multi-chain, flash-loan-backed liquidation bot — written in Rust. + +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) +[![Rust](https://img.shields.io/badge/rust-edition_2024-orange.svg)](https://www.rust-lang.org/) +[![Status](https://img.shields.io/badge/status-v0.1%20WIP-yellow.svg)](#roadmap) + +Charon monitors under-collateralized positions across major DeFi lending protocols and executes profitable liquidations using flash loans — **zero upfront capital, zero position risk**. If a liquidation turns out to be unprofitable at execution time, the entire transaction reverts atomically; the only cost is a failed simulation's gas. + +> Named after the mythological ferryman. Charon carries underwater positions to their final destination. + +--- + +## Table of Contents + +- [Status](#status) +- [How it works](#how-it-works) +- [Key features](#key-features) +- [Safety model](#safety-model) +- [Getting started](#getting-started) +- [Configuration](#configuration) +- [Project structure](#project-structure) +- [Roadmap](#roadmap) +- [Contributing](#contributing) +- [License](#license) + +--- + +## Status + +**v0.1 — work in progress.** The foundation is in place: Cargo workspace, normalized types, the `LendingProtocol` trait, a TOML config loader with env-var substitution, and a runnable CLI that validates and reports on the loaded config. Chain listening, health scanning, and on-chain execution arrive in the next phases of the build. + +**Current scope:** Venus Protocol on BNB Chain. Other protocols and chains are on the [roadmap](#roadmap). + +> ⚠️ **Do not run this against mainnet with real funds yet.** Nothing has been battle-tested. Treat v0.1 as development-only. + +--- + +## How it works + +```mermaid +flowchart LR + BNB[BNB Chain
WebSocket]:::chain + + subgraph Core["Charon Core — Rust"] + direction TB + L[Chain Listener] --> A[Venus Adapter] + A --> S[Health Scanner] + P[Price Engine
Chainlink + TWAP] --> S + S --> Pr[Profit Calculator] + Pr --> R[Flash Loan Router] + R --> B[Tx Builder] + end + + subgraph OnChain["On-chain — Solidity"] + direction TB + Liq[CharonLiquidator.sol] + F[Flash Loan Source
Aave V3 Pool] + D[DEX Swap
PancakeSwap / Uniswap V3] + V[Venus Protocol] + Liq --> F + Liq --> V + Liq --> D + end + + BNB --> L + B --> Liq + + classDef chain fill:#0f1e36,stroke:#3b82f6,color:#e2e8f0 +``` + +1. **Listen** — A WebSocket listener receives new blocks and log events from the chain. +2. **Decode** — Protocol adapters normalize raw events into a shared `Position` struct — the rest of the pipeline doesn't care whether the source is Venus, Aave, or anything else. +3. **Price** — A price engine reads live USD prices from Chainlink, with Uniswap V3 TWAPs as a fallback when Chainlink is unavailable or stale. +4. **Scan** — The health scanner recomputes health factors and flags any position that drops below `1.0`. +5. **Estimate** — The profit calculator simulates the full liquidation end-to-end (gas + flash-loan fee + expected DEX slippage) and drops anything below a per-chain USD threshold. +6. **Route** — The flash-loan router picks the cheapest available source (Balancer 0 % → Aave V3 0.05 % → Uniswap V3 pool fee). +7. **Build** — The transaction builder encodes the call, dry-runs it via `eth_call`, signs, and submits (via Flashbots on Ethereum, private RPC on L2s). +8. **Execute** — On-chain, `CharonLiquidator.sol` atomically: flash-borrows → calls the protocol's liquidation entry point → swaps seized collateral back to the debt token → repays the flash loan → forwards profit to the bot's hot wallet. If any step fails, the entire transaction reverts. + +--- + +## Key features + +- **Zero capital required.** Every liquidation is flash-loan-backed. No pre-funded position, no locked inventory. +- **Protocol-agnostic.** Adding a new lending protocol means implementing a single Rust trait (`LendingProtocol`). No changes to scanning, routing, or execution. +- **Multi-chain by design.** A single binary monitors multiple EVM chains in parallel. v0.1 ships BSC; v0.3 expands to Ethereum, Arbitrum, Polygon, Base, and Avalanche. +- **Rust performance.** `tokio` async runtime, lock-free concurrent state via `DashMap`, sub-50 ms block-to-broadcast latency target. Designed to run comfortably on a $5 VPS. +- **Flash-loan atomicity.** Bad slippage, race conditions, and math errors all revert the transaction — the protocol never loses its liquidity, and the bot never loses capital. +- **Open source, MIT licensed.** Community extensions welcome. + +--- + +## Safety model + +Every liquidation has the atomic form: + +``` +borrow (flash) → liquidate → swap → repay flash → profit +``` + +If the chain of operations cannot repay the flash loan in full, the EVM reverts the entire transaction — including the flash borrow itself. Concretely: + +| Failure mode | Outcome | +|---|---| +| Profit estimate was wrong | Tx reverts, flash source gets its capital back, bot pays only gas | +| DEX swap slippage exceeds slippage guard | Tx reverts atomically — no capital change | +| Another bot won the race | `eth_call` simulation catches 99 %+ before submit, so no gas spent | +| Oracle update mid-transaction pushes health back ≥ 1.0 | Tx reverts on the liquidation call | + +**Worst case:** gas for a single failed transaction (typically $0.01–$5 depending on chain). +**Best case:** profit lands in the bot's hot wallet. +**No intermediate case** where bot capital is lost — this is the fundamental guarantee of flash-loan design. + +--- + +## Getting started + +### Prerequisites + +- **Rust** — edition 2024 / `rustc 1.85+`. Install via [rustup.rs](https://rustup.rs/). +- **A BNB Chain RPC endpoint** — `.env.example` ships with public-node defaults (good for light testing, rate-limited in production). For real use, point it at a private endpoint (QuickNode, Ankr, Blast, or your own node). + +### Clone and build + +```bash +# via HTTPS +git clone https://github.com/obchain/Charon.git + +# or via SSH +git clone git@github.com:obchain/Charon.git + +cd Charon +cargo build +``` + +### Configure + +```bash +cp .env.example .env +# edit .env with your RPC endpoints +``` + +### Run + +```bash +cargo run -- --config config/default.toml listen +``` + +Expected output (v0.1 — scanner not wired up yet): + +``` +INFO charon: charon starting up +INFO charon: loading config path=config/default.toml +INFO charon: config loaded chains=1 protocols=1 flashloan_sources=1 liquidators=1 min_profit_usd=5 +INFO charon: listen: not wired up yet — scanner arrives in Day 2 +``` + +For verbose logs, prepend `RUST_LOG=debug`. + +--- + +## Configuration + +Charon reads a TOML config file (default path: `config/default.toml`). Secrets — RPC URLs, keys, API tokens — are referenced as `${ENV_VAR}` placeholders and substituted from the process environment (or a local `.env` file) at load time. + +Example (abridged): + +```toml +[bot] +min_profit_usd = 5.0 # drop opportunities below this threshold +max_gas_gwei = 10 # skip when gas spikes beyond this +scan_interval_ms = 1000 # polling cadence (ms) + +[chain.bnb] +chain_id = 56 +ws_url = "${BNB_WS_URL}" +http_url = "${BNB_HTTP_URL}" + +[protocol.venus] +chain = "bnb" +comptroller = "0xfd36e2c2a6789db23113685031d7f16329158384" + +[flashloan.aave_v3_bsc] +chain = "bnb" +pool = "0x6807dc923806fe8fd134338eabca509979a7e0cb" +``` + +Environment variables expected by the default config: + +| Variable | Purpose | +|---|---| +| `BNB_WS_URL` | BNB Chain WebSocket RPC endpoint | +| `BNB_HTTP_URL` | BNB Chain HTTPS RPC endpoint (for multicall) | + +--- + +## Project structure + +``` +Charon/ +├── crates/ +│ ├── charon-core/ # Shared types, LendingProtocol trait, config loader +│ ├── charon-scanner/ # Chain listener + health-factor scanner (v0.1 WIP) +│ └── charon-cli/ # Command-line binary (`charon`) +├── config/ +│ └── default.toml # Default configuration (Venus on BNB) +├── .env.example # Environment variable template +└── Cargo.toml # Workspace root + shared dependency versions +``` + +Crates planned for later phases: + +- **`charon-protocols/`** — per-protocol adapters (Venus, Aave V3, Compound V3, Morpho, …) +- **`charon-flashloan/`** — flash-loan source router +- **`charon-executor/`** — transaction builder, batcher, gas strategy, nonce manager +- **`charon-telemetry/`** — Prometheus metrics + Telegram alerting +- **`contracts/`** — Foundry workspace housing `CharonLiquidator.sol` + +--- + +## Roadmap + +Tracked on GitHub: [obchain/Charon › Milestones](https://github.com/obchain/Charon/milestones). + +### v0.1 — Venus on BNB *(current)* + +- [x] Cargo workspace + three-crate skeleton +- [x] Core types (`Position`, `LiquidationOpportunity`, `FlashLoanSource`, `SwapRoute`, …) +- [x] `LendingProtocol` trait +- [x] TOML config loader with env-var substitution +- [x] CLI with `--config` flag and `listen` subcommand +- [ ] Venus adapter — fetch positions, compute liquidation params +- [ ] Chainlink price engine (with Uniswap V3 TWAP fallback) +- [ ] Health-factor scanner + near-liquidation cache +- [ ] `CharonLiquidator.sol` (Foundry) + deploy script +- [ ] Flash-loan router (Aave V3 on BSC) +- [ ] DEX swap optimizer (PancakeSwap / Uniswap V3) +- [ ] Transaction builder with `eth_call` simulation +- [ ] Prometheus metrics + Telegram alerts +- [ ] Docker Compose deployment + +### v0.2 — Multi-protocol *(planned)* + +- Aave V3 adapter +- Compound V3 adapter +- Morpho Blue adapter +- Protocol-specific close-factor handling + +### v0.3 — Multi-chain *(planned)* + +- Ethereum Mainnet (with Flashbots bundle submission) +- Arbitrum One +- Polygon PoS +- Base +- Avalanche C-Chain + +--- + +## Contributing + +Contributions are welcome. A few ground rules: + +1. **Open an issue first** for non-trivial changes, so the design can be discussed before code is written. +2. **One logical change per PR.** Keep commits focused and follow conventional titles (`feat(core):`, `fix(scanner):`, `chore:`, etc.). +3. **Respect the crate boundaries.** Protocol changes live in `charon-protocols/`, execution changes in `charon-executor/`. Shared types belong in `charon-core`. +4. **No secrets in the repo — ever.** `.env` is git-ignored. Keep it that way. + +New to the codebase? Check issues tagged [`good first issue`](https://github.com/obchain/Charon/labels/good%20first%20issue). + +--- + +## License + +MIT — see [LICENSE](LICENSE). From 38e7eac6be39eeb3f07c2072c254a5f483bdd1e5 Mon Sep 17 00:00:00 2001 From: obchain Date: Wed, 22 Apr 2026 20:04:01 +0530 Subject: [PATCH 2/2] chore: enforce md policy + add Foundry/node_modules ignores - Untrack CLAUDE.md; root-level CLAUDE.md stays local-only. - .gitignore: *.md / !README.md glob enforces the markdown policy. - .gitignore: add Foundry artifacts (out/, cache/, broadcast/) at root and under contracts/ so forge build/script output stays local. - .gitignore: add node_modules/ for any npm-based contract deps or operator tooling. Closes #56 #57 #58 #59 --- .gitignore | 15 +++++++++++ CLAUDE.md | 78 ------------------------------------------------------ 2 files changed, 15 insertions(+), 78 deletions(-) delete mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore index 1381a72..56ffaa1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,17 @@ /target/ **/*.rs.bk +# Foundry build artifacts +contracts/out/ +contracts/cache/ +contracts/broadcast/ +out/ +cache/ +broadcast/ + +# JS/TS tooling +node_modules/ + # Environment / secrets .env .env.local @@ -16,6 +27,10 @@ # Logs *.log +# Markdown policy: only README.md is ever pushed; everything else is local-only. +*.md +!README.md + # Local-only dev notes and editor configs .claude/ docs/context.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 6a44798..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,78 +0,0 @@ -# CLAUDE.md - -Global rules for any assistant (Claude Code or otherwise) working in -this repository. Humans contributing through a PR review get the same -rules by convention — but these are hard constraints for automated -tools. - ---- - -## Commits - -- NEVER add a `Co-Authored-By` line. -- Author + committer must be the human operator of the repo; never - an assistant, bot, or pair-programming identity. -- Commit messages describe the technical change only. No references - to AI tools, prompts, models, or this file. -- Follow Conventional Commits. Prefixes in use: `feat()`, - `fix()`, `chore`, `docs`, `test`, `refactor`, `perf`. - Subject ≤ 70 chars, imperative mood, lowercase. -- No emoji in subjects unless a PR template explicitly calls for it. - -## Branches and PRs - -- `main` is protected. **Never push directly to main.** Every change - lands via a pull request. -- One branch per GitHub issue: `feat/-`, `fix/-`, - `chore/-`. -- PR title mirrors the squash-merge subject. PR body must include - `Closes #` (or `Refs #` for partial progress) so the issue - tracker stays in sync. -- Squash-merge on acceptance. One commit per PR on `main`. -- PR descriptions: technical only. Same rule as commit messages — no - AI references. - -## Issues - -- Issue titles use a `[layer] subject` prefix, e.g. - `[scanner] Chainlink PriceCache staleness check`. -- Every issue carries `type:*`, `layer:*`, `priority:*`, `status:*` - labels and a milestone. -- Issue comments and closures: technical only, no AI references. - -## Workflow - -- Before any commit: run the gates locally. - - Rust: `cargo fmt --all`, `cargo clippy --workspace --all-targets - --all-features -- -D warnings`, `cargo test --workspace`. - - Solidity (Foundry, inside `contracts/`): - `forge build`, `forge fmt --check`, `forge test`. -- A pre-commit hook (local, not tracked) enforces the Rust gates on - any assistant-driven commit. Do not bypass with `--no-verify`. - -## Scope (v0.1) - -- **Venus protocol on BNB Chain only.** Multi-chain / multi-protocol - expansion is a config change later, not a rewrite. -- Secrets (`.env`, private keys, API tokens) **never** go into the - repo. Use `${ENV_VAR}` substitution in `config/default.toml`. - -## Safety invariants - -- The bot hot wallet holds gas only. Profit is swept to the cold - wallet inside every flash-loan callback. Do not introduce code that - parks profit in the hot wallet. -- Every liquidation transaction passes an `eth_call` simulation gate - before broadcast. Do not add a bypass. -- `CharonLiquidator.executeLiquidation` is `onlyOwner`. Do not weaken - or remove the modifier. -- Flash-loan atomicity is the last line of defense, not the first. - Off-chain gates (health factor, price freshness, profitability, gas - ceiling, flash-loan liquidity) must all run before simulation. - -## What not to track - -- Build artifacts (`target/`, `contracts/out/`, `contracts/cache/`). -- Editor configs (`.idea/`, `.vscode/`). -- Local-only notes and dev collaboration files. -- Anything containing secrets.