feat(compound-v2-plugin): initial release v0.1.0 — Compound V2 exit tool#42
Conversation
📋 Phase 3: AI Code Review Report — Score: N/A/100
❌ AI review FAILED (HTTP 400): Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.. Request size: 1246219 bytes, plugin content: 178604 bytes. Generated by Claude AI via Anthropic API — review the full report before approving. |
🔨 Phase 2: Build Verification — ✅ PASSED
Build succeeded. Compiled artifact uploaded as workflow artifact. Source integrity: commit SHA `` is the content fingerprint. |
🔨 Phase 2: Build Verification — ✅ PASSED
Build succeeded. Compiled artifact uploaded as workflow artifact. Source integrity: commit SHA `` is the content fingerprint. |
✅ Phase 1: Structure Validation — PASSED→ Proceeding to Phase 2: Build Verification |
Compound V2 (cToken-based) money market integration on Ethereum mainnet,
positioned as an EXIT tool for legacy positions. As of 2026, all 6 major
markets (cDAI / cUSDC / cUSDT / cETH / cWBTC2 / cCOMP) have governance-paused
new supply AND borrow (mintGuardianPaused = borrowGuardianPaused = true).
Compound team's active development is on V3 (Comet); this plugin's pre-flight
checks short-circuit supply/borrow with structured MARKET_PAUSED_USE_V3 /
BORROW_PAUSED_USE_V3 errors that explicitly redirect users to compound-v3-plugin.
Commands (10):
- quickstart: scans 6 cTokens for wallet/supply/borrow + accrued COMP, returns
6-state status enum (rpc_degraded / protocol_winddown / has_supply_can_redeem
/ has_debt_can_repay / has_comp_accrued / insufficient_gas) with
ready-to-run next_command
- markets: per-cToken APRs, TVL, utilization, pause flags
- positions: per-cToken supply + borrow + COMP accrued, account_liquidity,
assets_in (entered as collateral)
- supply: pre-flight mint-paused check → V3 redirect; full mint(amount)
flow (cETH payable mint() for native) preserved for future
- withdraw: cToken.redeemUnderlying(amount); --amount all redeems exact
current supply
- borrow: pre-flight borrow-paused + getAccountLiquidity check → V3 redirect;
auto enterMarkets + cToken.borrow flow preserved
- repay: --all uses uint256.max sentinel (Compound V2 native max-sentinel,
contract caps to current debt) → exact-zero dust guarantee, addresses
LEND-001. cETH payable repay path
- claim-comp: Comptroller.claimComp(holder, address[] cTokens); reports
before/after COMP balance diff for actual claim amount
- enter-markets / exit-market: collateral set management
Selectors (all keccak-verified + on-chain eth_call tested):
cToken (CErc20 / CEther):
mint(uint256) 0xa0712d68 / mint() 0x1249c58b
redeemUnderlying(uint256) 0x852a12e3 / redeem(uint256) 0xdb006a75
borrow(uint256) 0xc5ebeaec / repayBorrow(uint256) 0x0e752702
balanceOfUnderlying / borrowBalanceCurrent / supplyRatePerBlock /
borrowRatePerBlock / exchangeRateStored / totalBorrows / underlying
Comptroller (Unitroller proxy 0x3d9819…9c9Cd3B):
enterMarkets 0xc2998238 / exitMarket 0xede4edd0
claimComp(address, address[]) 0x1c3db2e0
compAccrued / getAllMarkets / getAccountLiquidity / getAssetsIn / markets
mintGuardianPaused 0x731f0c2b / borrowGuardianPaused 0x6d154ea5
Build-time selector bug caught: initial guess for borrowGuardianPaused
selector (0x6d35bf91) was wrong — actual is 0x6d154ea5. Wrong selector
silently reverted; my fail-closed unwrap_or(true) in supply/borrow correctly
trapped (refused write), but read-side is_borrow_paused.unwrap_or(false)
silently displayed 'false' across markets/quickstart. Fixed across rpc.rs;
re-verified all 6 markets show borrow_paused=true post-fix.
Knowledge base compliance: GEN-001 / ONB-001 / ONC-001 / EVM-001 / EVM-002
/ EVM-006 / EVM-014 (3-pattern allowance-lag retry) / EVM-015 (per-op
gas-limits: approve 80k, redeem/repay 280k, borrow 450k, claimComp 200k+70k×N)
/ TX-001 (wait_for_tx + on_chain_status field) / GAS-001 (0.005 ETH floor for
L1 mainnet) / LEND-001 (uint256.max repay sentinel — exact-zero dust,
single-tx, simpler than Dolomite's branching since Compound caps internally).
Verified end-to-end on Ethereum mainnet: read commands return real on-chain
APRs (cUSDC borrow 3.82%, cETH borrow 1.74%, cWBTC2 borrow 2.11%); pause
flags correctly show all 6 markets paused; supply/borrow correctly
short-circuit with V3 redirect; withdraw/repay/exit-market return correct
NO_SUPPLY/NO_DEBT/NOT_IN_MARKET errors on user with no V2 history.
v0.1.0 scope: Ethereum mainnet only. V2 was never deployed officially on other
chains (BSC/Polygon "V2" instances are non-official forks: Venus / CREAM).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ml description CI Phase 1 lint panics on UTF-8 multi-byte chars in description due to string slicing assuming char boundaries (src/submission/lint.rs:946). Em-dash "—" (U+2014, 3-byte UTF-8) caused panic at byte index inside char. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI Phase 1 lint requires:
- schema_version: 1
- author: { name, github } struct (not bare string)
- category, license, components, build sections
- "binary:" stanza was a my-format invention not in spec
Aligned to dolomite-plugin's already-passing schema.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ription Phase 1 lint also reads SKILL.md frontmatter, not just plugin.yaml. The earlier plugin.yaml em-dash fix wasn't enough — frontmatter description contained another em-dash, panicking lint.rs:946:36. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same root cause as dolomite — Phase 1 lint reads SKILL.md frontmatter and panics on multi-byte UTF-8 (lint.rs:946:36). Conservatively strip non-ASCII across SKILL.md body too: arrows, x, warning sigil, ellipsis -> ASCII equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lint Phase 1 lint [E106] requires user confirmation language nearby any 'wallet contract-call' mention in SKILL.md. Expanded ONC-001 row in compliance table to explicitly note that all 7 write commands require --confirm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nce section Same rationale as dolomite-plugin's removal: this compliance table is not required by maintenance rules, doesn't appear in any of the 25 other plugins in the repo, and its 'wallet contract-call' mention triggered E106 lint failures. Aligning with hyperliquid-plugin's reference structure (per user feedback): Pre-flight Dependencies / Trigger Phrases / Commands / Skill Routing / Security Notice / Do NOT Use For / Changelog. The user-relevant LEND-001 dust-free guarantee is already documented under the repay command section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…section Aligns with canonical SKILL.md template (skill-md-maintenance-guide.md §0.1): 'Data Trust Boundary' is the 2nd most common H2 section across 28 canonical skills (18/28 = 64%). Promoting from inline blockquote -> top-level H2 to match precedent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ance Phase 3 local AI review findings: 1. .claude-plugin/plugin.json description had 1 em-dash (U+2014). The skill-md-maintenance-guide §0.7 mandates ASCII for plugin.json (CI lint.rs:946 panics on em-dash). Replace with '-'. 2. 34 hardcoded function selectors in src/rpc.rs::selectors with zero runtime verification. A typo would silently misroute calls on chain. Add rpc::tests::selectors_match_keccak256 that recomputes every selector via keccak256 over the canonical signature and asserts equality. All 34 currently match (verified). Required adding sha3 + hex as dev-dependencies (not runtime deps -- keeps the binary lean). Pattern matches the runtime-selector test added to euler-v2-plugin / aave-v2-plugin / fourmeme-plugin during their reviews. Also added '.ai-review/' to '.gitignore' so locally-generated Phase 3 review artifacts don't leak into commits. Tests: 0/0 -> 1/1. ASCII compliance: 1 non-ASCII -> 0. Static scan own-source findings: 0 -> 0 (no regressions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…i-pattern) CLAUDE.md / skill-md-maintenance-guide §0.6 forbids exposing internal knowledge-base rule codes (e.g. LEND-001, EVM-001, ONC-001) in SKILL.md because external agents reading the doc do not have the knowledge base and cannot resolve what the codes mean. The intent should live in prose: 'this addresses dust-free repay' is useful; 'addresses **LEND-001**' is internal jargon. Removed 1 occurrence of '**LEND-001**' from the repay command section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17a9a87 to
c578718
Compare
✅ Phase 4: Publish CompletePlugins:
Published by Plugin Store CI |
Summary
Compound V2 (cToken-based) money market integration on Ethereum mainnet, positioned as an EXIT tool for legacy positions.
As of 2026, all 6 major V2 markets (cDAI / cUSDC / cUSDT / cETH / cWBTC2 / cCOMP) have governance-paused both new supply (
mintGuardianPaused = true) and new borrow (borrowGuardianPaused = true). Compound team's active development is on V3 (Comet).This plugin's pre-flight short-circuits supply/borrow with structured
MARKET_PAUSED_USE_V3/BORROW_PAUSED_USE_V3errors, redirecting users tocompound-v3-plugin:$ compound-v2-plugin supply --token USDC --amount 100 --confirm { "ok": false, "error_code": "MARKET_PAUSED_USE_V3", "suggestion": "Install compound-v3-plugin: `npx skills add okx/plugin-store --skill compound-v3-plugin`" }10 commands
quickstart(6-state status enum) /markets/positionswithdraw(redeemUnderlying) /repay(uint256.max sentinel for dust-free--all) /claim-compsupply/borrowenter-markets/exit-marketHighlights
cToken.repayBorrow(uint256.max)sentinel — contract auto-caps to current debt at execution time. Single-tx, no decision-tree complexity (simpler than Dolomite's branching A/B/C since Compound's contract handles the cap internally).mint()no-args +value=amount,repayBorrowno-approve +value=amount. Distinct from ERC-20mint(uint256)/repayBorrow(uint256)paths.eth_callsmoke test. Critical bug caught in dev: initial guess forborrowGuardianPaused(address)(0x6d35bf91) was wrong; correct is0x6d154ea5. Wrong selector silently reverted, which my fail-closedis_borrow_paused.unwrap_or(true)in write commands correctly trapped, but read-side displays were silently showingborrow_paused=false. Fixed; re-verified all 6 markets showborrow_paused=truepost-fix.0xbafe01ff…b526. Switched to live eth_call probe + keccak256-only verification.Knowledge base compliance
GEN-001 ✓ ONB-001 ✓ ONC-001 ✓ EVM-001 ✓ EVM-002 ✓ EVM-006 ✓ EVM-014 (3 patterns) ✓ EVM-015 (80k/280k/450k/200k+70k×N) ✓ TX-001 ✓ GAS-001 (0.005 ETH floor for L1 mainnet) ✓ LEND-001 ✓
Test plan
cargo buildclean (warnings only — unused selector consts kept for reference)--help↔ SKILL.md flag parityethereum-rpc.publicnode.com)0.1.0(plugin.yaml, SKILL.md frontmatter, Cargo.toml, .claude-plugin/plugin.json)0x87fb…1b90, no V2 history):quickstart→status: protocol_winddown,next_command: npx skills add ... --skill compound-v3-plugin✓markets→ 6 markets, allmint_paused=true && borrow_paused=true, real APRs (cUSDC 3.82%, cETH 1.74%) ✓positions→position_count: 0,comp_accrued: 0,assets_in: []✓supply --token USDC --amount 1 --confirm→MARKET_PAUSED_USE_V3✓borrow --token DAI --amount 1 --confirm→BORROW_PAUSED_USE_V3✓withdraw --token DAI --amount 1 --confirm→NO_SUPPLY✓repay --token USDC --all --confirm→NO_DEBT✓claim-comp --dry-run→compAccrued: 0displayed ✓enter-markets --ctokens cDAI --dry-run→ preview correct,currently_entered: []✓exit-market --ctoken cDAI --confirm→NOT_IN_MARKET✓{ok:false, error_code, suggestion}JSON via stdout (GEN-001)🤖 Generated with Claude Code