feat(puffer-plugin): Puffer Finance liquid restaking (v0.1.0)#30
Conversation
🔨 Phase 2: Build Verification — ✅ PASSED
Build succeeded. Compiled artifact uploaded as workflow artifact. Source integrity: commit SHA `` is the content fingerprint. |
📋 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: 1069501 bytes, plugin content: 156445 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. |
… command (CI E151 + ONB-001) CI Phase 1 reported 3 errors + 1 warning on PR mig-pre#30: - [E151] SUMMARY.md missing required section: '## Overview' - [E151] SUMMARY.md missing required section: '## Prerequisites' - [E151] SUMMARY.md missing required section: '## Quick Start' - [W010] description is 208 chars (recommended < 200) Root cause: SUMMARY.md was using a non-standard `# puffer` + `## Highlights` layout — pre-dates the now-mandatory three-section template. plugin.yaml description was also too long. While fixing, also discovered puffer-plugin was missing the `quickstart` command altogether — a violation of the new ONB-001 三件套 mandatory structure (quickstart command + SUMMARY.md + LICENSE). Without quickstart, SUMMARY's "step 1 = quickstart" rule can't be satisfied either. Changes: 1. Added src/commands/quickstart.rs — 4 status enum (rpc_degraded / no_funds / ready_to_stake / has_pufeth_earning); parallel reads of ETH balance + pufETH balance + rate + APY + ETH price; returns ready-to-run next_command per status. 2. Wired quickstart into commands/mod.rs and main.rs (with import, enum variant, dispatch arm). 3. Rewrote SUMMARY.md to three-section template (Overview / Prerequisites / Quick Start), with step 1 = quickstart and steps 2..7 mapping to status enum values + the queued-withdrawal flow for completeness. 4. Shortened plugin.yaml description from 221 to 192 chars (W010 fix). Verified locally: - cargo build: clean - puffer-plugin quickstart: returns status=ready_to_stake with ETH=0.0935 + APY=3.03% + next_command="puffer-plugin stake --amount 0.05 --confirm" - All Step 1.6 staleness checks pass: SUMMARY 三段式 ✓, 第 1 步 quickstart ✓, status enum src↔doc 一致 ✓, LICENSE present ✓ - description 192 chars (< 200) ✓ - 9 commands now: quickstart + 8 existing Reuses existing PR mig-pre#30 — no new PR opened. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 local AI review (PR mig-pre#30) findings: 1. Non-ASCII chars in 4 metadata files where ASCII is mandated by skill-md-maintenance-guide §0.7 (CI lint.rs:946 panics on em-dash): plugin.yaml: 1 em-dash .claude-plugin/plugin.json: 1 em-dash SKILL.md frontmatter: 2 (em-dash + LEFT-RIGHT-ARROW '<->') SUMMARY.md: 6 em-dashes Replace U+2014 -> '-', U+2194 -> '<->', U+2192 -> '->', U+2265 -> '>=', U+2264 -> '<=', U+2026 -> '...'. SKILL.md body left untouched. 2. 7 hardcoded function selectors in src/calldata.rs are inlined as format!() literals (e.g. format!("0x6e553f65{}{}", ...)) instead of `pub const` -- no runtime verification existed. A typo would silently misroute calls. Add calldata::tests::selectors_match_keccak256 with keccak-recomputed assertions on all 7: - depositETH(address) - deposit(uint256,address) (ERC-4626, reserved for v0.2) - redeem(uint256,address,address) - withdraw(uint256,address,address) - requestWithdrawal(uint128,address) - completeQueuedWithdrawal(uint256) - approve(address,uint256) Required adding sha3 as a dev-dependency (hex was already a runtime dep). Pattern matches euler-v2 / aave-v2 / compound-v2 / dolomite / spark-savings / fourmeme. Also added '.ai-review/' to '.gitignore'. Tests: 0/0 -> 1/1. ASCII compliance: 10 non-ASCII -> 0. Static scan own-source findings: 0 -> 0 (no regressions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 local AI review (PR mig-pre#30) findings: 1. Non-ASCII chars in 4 metadata files where ASCII is mandated by skill-md-maintenance-guide §0.7 (CI lint.rs:946 panics on em-dash): plugin.yaml: 1 em-dash .claude-plugin/plugin.json: 1 em-dash SKILL.md frontmatter: 2 (em-dash + LEFT-RIGHT-ARROW '<->') SUMMARY.md: 6 em-dashes Replace U+2014 -> '-', U+2194 -> '<->', U+2192 -> '->', U+2265 -> '>=', U+2264 -> '<=', U+2026 -> '...'. SKILL.md body left untouched. 2. 7 hardcoded function selectors in src/calldata.rs are inlined as format!() literals (e.g. format!("0x6e553f65{}{}", ...)) instead of `pub const` -- no runtime verification existed. A typo would silently misroute calls. Add calldata::tests::selectors_match_keccak256 with keccak-recomputed assertions on all 7: - depositETH(address) - deposit(uint256,address) (ERC-4626, reserved for v0.2) - redeem(uint256,address,address) - withdraw(uint256,address,address) - requestWithdrawal(uint128,address) - completeQueuedWithdrawal(uint256) - approve(address,uint256) Required adding sha3 as a dev-dependency (hex was already a runtime dep). Pattern matches euler-v2 / aave-v2 / compound-v2 / dolomite / spark-savings / fourmeme. Also added '.ai-review/' to '.gitignore'. Tests: 0/0 -> 1/1. ASCII compliance: 10 non-ASCII -> 0. Static scan own-source findings: 0 -> 0 (no regressions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
79d81c1 to
2e6af55
Compare
✅ Phase 1: Structure Validation — PASSED→ Proceeding to Phase 2: Build Verification |
skill-md-maintenance-guide §0.6 explicitly forbids '## Roadmap' / '## TODO' / '## Known Issues' as SKILL.md sections: 'these are GitHub issue territory, not SKILL.md'. PR mig-pre#30 had a '## Roadmap (future versions)' H2 with 4 v0.2.x / v0.3.x / v0.x.x bullets. Removed the H2 + bullets. Future-version notes belong in PR descriptions, GitHub issues, or the Recommendations section of review reports -- not in user-facing SKILL.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First release: deposit ETH to mint pufETH via PufferVault, and exit
through either the 1-step instant redeem (pays live exit fee from
getTotalExitFeeBasisPoints, default 1%) or the 2-step queued
withdraw (fee-free, ~14 days, 0.01 pufETH minimum).
8 commands:
positions, rate, withdraw-options — read-only
withdraw-status — track a queued request
stake — depositETH payable
request-withdraw, claim-withdraw — 2-step queued path
instant-withdraw — 1-step redeem path
Each write command prints structured JSON to stdout so external
agents can branch on stable error_code (INSUFFICIENT_BALANCE,
INSUFFICIENT_GAS, WITHDRAWAL_AMOUNT_TOO_LOW / _TOO_HIGH /
_NOT_FINALIZED / _ALREADY_CLAIMED / _OUT_OF_RANGE,
TX_WILL_REVERT, TX_CONFIRMATION_TIMEOUT, RPC_ERROR).
Pre-flight checks before every broadcast:
- input-asset balance via onchainos wallet balance
- vault liquidity / per-request max / min amount
- gas budget: onchainos gateway gas-limit + gas,
wallet ETH balance must cover value + gas*1.2
- revert simulation; onchainos surfaces the revert reason
Broadcast and confirmation use onchainos wallet contract-call and
wallet history polling (no sleep-based races; waits every tx until
SUCCESS before reading post-tx state). Custom contract view
functions (convertToAssets, getMaxWithdrawalAmount, getWithdrawal,
allowance, etc.) use direct eth_call — onchainos has no generic
view interface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… command (CI E151 + ONB-001) CI Phase 1 reported 3 errors + 1 warning on PR mig-pre#30: - [E151] SUMMARY.md missing required section: '## Overview' - [E151] SUMMARY.md missing required section: '## Prerequisites' - [E151] SUMMARY.md missing required section: '## Quick Start' - [W010] description is 208 chars (recommended < 200) Root cause: SUMMARY.md was using a non-standard `# puffer` + `## Highlights` layout — pre-dates the now-mandatory three-section template. plugin.yaml description was also too long. While fixing, also discovered puffer-plugin was missing the `quickstart` command altogether — a violation of the new ONB-001 三件套 mandatory structure (quickstart command + SUMMARY.md + LICENSE). Without quickstart, SUMMARY's "step 1 = quickstart" rule can't be satisfied either. Changes: 1. Added src/commands/quickstart.rs — 4 status enum (rpc_degraded / no_funds / ready_to_stake / has_pufeth_earning); parallel reads of ETH balance + pufETH balance + rate + APY + ETH price; returns ready-to-run next_command per status. 2. Wired quickstart into commands/mod.rs and main.rs (with import, enum variant, dispatch arm). 3. Rewrote SUMMARY.md to three-section template (Overview / Prerequisites / Quick Start), with step 1 = quickstart and steps 2..7 mapping to status enum values + the queued-withdrawal flow for completeness. 4. Shortened plugin.yaml description from 221 to 192 chars (W010 fix). Verified locally: - cargo build: clean - puffer-plugin quickstart: returns status=ready_to_stake with ETH=0.0935 + APY=3.03% + next_command="puffer-plugin stake --amount 0.05 --confirm" - All Step 1.6 staleness checks pass: SUMMARY 三段式 ✓, 第 1 步 quickstart ✓, status enum src↔doc 一致 ✓, LICENSE present ✓ - description 192 chars (< 200) ✓ - 9 commands now: quickstart + 8 existing Reuses existing PR mig-pre#30 — no new PR opened. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 local AI review (PR mig-pre#30) findings: 1. Non-ASCII chars in 4 metadata files where ASCII is mandated by skill-md-maintenance-guide §0.7 (CI lint.rs:946 panics on em-dash): plugin.yaml: 1 em-dash .claude-plugin/plugin.json: 1 em-dash SKILL.md frontmatter: 2 (em-dash + LEFT-RIGHT-ARROW '<->') SUMMARY.md: 6 em-dashes Replace U+2014 -> '-', U+2194 -> '<->', U+2192 -> '->', U+2265 -> '>=', U+2264 -> '<=', U+2026 -> '...'. SKILL.md body left untouched. 2. 7 hardcoded function selectors in src/calldata.rs are inlined as format!() literals (e.g. format!("0x6e553f65{}{}", ...)) instead of `pub const` -- no runtime verification existed. A typo would silently misroute calls. Add calldata::tests::selectors_match_keccak256 with keccak-recomputed assertions on all 7: - depositETH(address) - deposit(uint256,address) (ERC-4626, reserved for v0.2) - redeem(uint256,address,address) - withdraw(uint256,address,address) - requestWithdrawal(uint128,address) - completeQueuedWithdrawal(uint256) - approve(address,uint256) Required adding sha3 as a dev-dependency (hex was already a runtime dep). Pattern matches euler-v2 / aave-v2 / compound-v2 / dolomite / spark-savings / fourmeme. Also added '.ai-review/' to '.gitignore'. Tests: 0/0 -> 1/1. ASCII compliance: 10 non-ASCII -> 0. Static scan own-source findings: 0 -> 0 (no regressions). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
skill-md-maintenance-guide §0.6 explicitly forbids '## Roadmap' / '## TODO' / '## Known Issues' as SKILL.md sections: 'these are GitHub issue territory, not SKILL.md'. PR mig-pre#30 had a '## Roadmap (future versions)' H2 with 4 v0.2.x / v0.3.x / v0.x.x bullets. Removed the H2 + bullets. Future-version notes belong in PR descriptions, GitHub issues, or the Recommendations section of review reports -- not in user-facing SKILL.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b4b4636 to
74ff99c
Compare
✅ Phase 4: Publish CompletePlugins:
Published by Plugin Store CI |
For new-plugin PRs, Phase 4 published the merge to main but never
created the GitHub release/tag. Symptom: PR shows merged, plugin files
on main, but `gh release list` has no entry and Create Release job
log says:
##[warning] skills/<plugin>/plugin.yaml not found,
skipping release for <plugin>
Why: create-release runs `actions/checkout@v4` against main, then
loops over BUILD_PLUGINS and reads `skills/$NAME/plugin.yaml`. For new
plugins that file does not exist on main yet — the merge happens later
in the publish-registry job — so it bails with the "skipping" warning
while the workflow stays green.
publish-registry already has the right pattern (see step "Checkout PR
head" at L612). Mirroring it in create-release:
- name: Checkout PR head
if: inputs.pr_number != ''
env:
PR_NUM: ${{ github.event.pull_request.number || inputs.pr_number }}
run: |
git fetch origin "refs/pull/${PR_NUM}/head:pr-head"
git checkout pr-head
Adds `fetch-depth: 0` to the initial checkout so the fetch above can
resolve refs/pull/N/head without a shallow-fetch error.
The conditional `inputs.pr_number != ''` skips this in
rebuild-all/manual-dispatch mode where main is already the source of
truth.
Build version is still pinned via BUILD_PLUGINS JSON, so the existing
"DO NOT git pull here" invariant from L480 is preserved — yq calls
read description/author from PR head, which matches the binaries that
were just compiled.
Concrete failures this fixes:
- mig-pre PR #30 puffer-plugin v0.1.0 (manual release made post-hoc)
- mig-pre PR #34 lifi-plugin v0.1.0 (still missing release as of writing)
- mig-pre PR #37 spark-savings-plugin v0.1.0 (still missing release as of writing)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
(1-step instant with live exit fee, 2-step queued fee-free ~14d)
error_codeand
gas_checkobject so external agents can branch deterministically`wallet history` polling); gas price / gas-limit / native + ERC-20 balance for
the connected wallet also go through `onchainos gateway gas` /
`gateway gas-limit` / `wallet balance`. Custom contract view functions
(convertToAssets, getMaxWithdrawalAmount, getWithdrawal, allowance, …) use
direct eth_call since onchainos has no generic view channel.
Commands
Pre-flight checks on every write command
`onchainos wallet balance` native ETH. Bails with INSUFFICIENT_GAS before
touching broadcast.
Error codes (stable for agents)
`INSUFFICIENT_BALANCE`, `INSUFFICIENT_GAS`, `WITHDRAWAL_AMOUNT_TOO_LOW`,
`WITHDRAWAL_AMOUNT_TOO_HIGH`, `WITHDRAWAL_NOT_FINALIZED`,
`WITHDRAWAL_ALREADY_CLAIMED`, `WITHDRAWAL_OUT_OF_RANGE`, `TX_WILL_REVERT`,
`TX_CONFIRMATION_TIMEOUT`, `RPC_ERROR`, `UNKNOWN_ERROR`.
Test plan
— rate 1.074330, exit_fee 100 bps, finalized_batch 1220, 12,283 requests
`withdraw-options` math checks (0.3 pufETH → 0.322299 gross, 0.319076 after 1% fee)
already claimed, not finalized, out of range — each maps to the right
`error_code` and `suggestion`
Future versions
WETH deposit path on `stake`
🤖 Generated with Claude Code