Skip to content
Open
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
62 changes: 62 additions & 0 deletions skills/maple-onchainos/FILL-IN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# FILL-IN — maple-onchainos implementation checklist

Status as of v0.1.0: **all 5 tools implemented; live-read against Ethereum mainnet validated.**

## Tool 1 — `listSupportedPools`

- [x] Returns curated set (syrupUSDC, syrupUSDT on Ethereum).
- [x] Optional `chain` filter.
- [ ] Roadmap: Base pool addresses (need to confirm canonical user-facing addresses; SDK only ships infrastructure addresses).

## Tool 2 — `getPool`

- [x] viem ERC-4626 reads: `symbol`, `asset`, `totalAssets`, `totalSupply`, `previewDeposit(1 unit)`.
- [x] Pool address validated against curated registry → `UNKNOWN_POOL` on miss.
- [x] `formatUnits` applied to `totalAssets` using known decimals.
- [ ] Roadmap: surface APY by reading `WithdrawalManager` or computing from `previewDeposit` over time windows.

## Tool 3 — `getPosition`

- [x] Reads `balanceOf` and `convertToAssets`.
- [x] Returns 0-position note with next-step suggestion when shares==0.
- [ ] Roadmap: surface pending redemption requests (Maple's withdrawal queue) — needs WithdrawalManager ABI.

## Tool 4 — `buildDeposit`

- [x] Reads underlying asset from `pool.asset()` (not user-supplied — prevents spoofed-asset attacks).
- [x] Allowance check → emit approve `pending_sign` (Step 1 of 2) if insufficient.
- [x] Underlying-balance pre-flight (INSUFFICIENT_BALANCE before broadcast).
- [x] Native-balance gate (P1-14, no-op for value=0 but wired uniformly).
- [x] viem `encodeFunctionData` for `deposit(uint256,address)`.
- [x] Receiver defaults to walletAddress; optional override validated.
- [ ] Roadmap: `permit` (ERC-2612) variant to skip the approve tx on permit-enabled tokens (USDC supports it, USDT does not).

## Tool 5 — `buildQueueWithdrawal`

- [x] Validates user holds enough shares before emitting.
- [x] Calls `requestRedeem(shares, owner)` — Maple's cycle-based queue.
- [x] Description makes the "not instant" semantics explicit (P1-16 — fee-mutation/flow ambiguity surfaced in description field).
- [ ] Roadmap: `claimRedemption` tool for after the cycle settles (need WithdrawalManager `processRedemptions` / `claim` ABI).

## Cross-cutting

- [x] All EVM addresses pass through `lc()` to satisfy viem's strict EIP-55.
- [x] `parseUnits` always paired with a known `decimals` from the pool registry (no user-supplied decimals — that class of error is dodged structurally, A7-equivalent).
- [x] Error taxonomy matches SKILL.md catalog (UNSUPPORTED_CHAIN, UNKNOWN_POOL, INSUFFICIENT_BALANCE, NO_POSITION, RPC_ERROR).
- [x] No local-signing residue (only `viem.encodeFunctionData` + `viem.readContract`).

## API quirks checklist (P1-16)

The Maple SDK has no boolean fee-mutation flags (unlike deBridge's `prependOperatingExpenses`). Notes for future tools:

| Pattern | Status |
|---|---|
| Fee-mutation flags | n/a — Maple is fee-free at the protocol entrypoint; APY is implicit in `convertToAssets` |
| Slippage | n/a — pool deposits are mint-at-current-rate, no slippage param |
| Affiliate fee | n/a |
| Pool whitelisting | **YES** — some Maple pools have `PoolPermissionManager` gating (KYC, allowlist). syrupUSDC/syrupUSDT are open; if we add the "lender-only" Maple v2 pools later, we'd need to surface `canDeposit(user)` checks in `buildDeposit` |
| Withdrawal cycle timing | **YES** — `requestRedeem` is queued; `description` makes this explicit |

## Known SDK delta

`maple-labs/maple-js` v3 `generateUnsignedTransactionData` uses **ethers v5** (`@ethersproject/*` packages). This skill uses **viem** instead. The output (an `unsigned_tx` with `to/data/value`) is functionally equivalent. The SDK additionally fills in `nonce`, `gasLimit`, `maxFeePerGas`, `maxPriorityFeePerGas`, `chainId`, `type: 2` — Onchain OS fills these at broadcast time, so we strip them from the envelope.
21 changes: 21 additions & 0 deletions skills/maple-onchainos/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 OKX

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.
128 changes: 128 additions & 0 deletions skills/maple-onchainos/QA-PIPELINE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# QA pipeline for maple-onchainos

Run AFTER `index.ts` is in place (it is — v0.1.0 is Form A complete).

## Pipeline overview

| Step | Skill | Live funds? | Status for v0.1.0 |
|---|---|---|---|
| 1. Static UX review | `explore-plugin` | ❌ | Run on each release |
| 2. Runnable build smoke | `tsx cli.ts` checks | ❌ | Required before every release |
| 3. Live RPC wiring | direct viem reads against mainnet | ❌ | Required before every release |
| 4. Regression sweep | `test-plugin` Phases 0/1/2/3/5 + A1-A8 self-checks | ❌ | Required to mark green |
| 5. Live broadcast | `test-plugin` + onchainos | **✅ YES — OPT-IN ONLY** | Last step |

## Step 1 — Static UX review

**Skill:** `explore-plugin`
**Trigger:** "explore plugin maple-onchainos"

Review:
- SKILL.md Command Index ↔ exports ↔ --help all in sync
- Withdrawal lifecycle described unambiguously (queue ≠ instant)
- Error-code catalog matches reality
- `prependOperatingExpenses`-style fee mutations called out? (n/a for Maple — see FILL-IN.md API quirks)

## Step 2 — Runnable build smoke

```bash
cd ~/.claude/skills/maple-onchainos
npm install
npx tsx cli.ts --version # → 0.1.0
npx tsx cli.ts --help # → lists 5 tools

# Read-only smoke
npx tsx cli.ts listSupportedPools '{}'
npx tsx cli.ts getPool '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b"}'

# Sample addresses for live-read tests:
# ethereum syrupUSDC: 0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b
# ethereum syrupUSDT: 0x356b8d89c1e1239cbbb9de4815c39a1474d5ba7d

# Position read (use any large depositor's address — public knowledge from Etherscan top holders)
npx tsx cli.ts getPosition '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b","walletAddress":"<addr>"}'

# Write-tool dry runs
npx tsx cli.ts buildDeposit '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b","amount":"10","walletAddress":"<your-wallet>"}'
npx tsx cli.ts buildQueueWithdrawal '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b","shares":"1","walletAddress":"<your-wallet>"}'
```

Confirm:
- All tools return well-formed JSON.
- `listSupportedPools` lists ≥ 2 pools.
- `getPool` returns `data.symbol === 'syrupUSDC'` (or syrupUSDT) and a non-zero `totalAssets`.
- `getPosition` returns shares=0 + suggestion note for a fresh wallet, OR positive shares + assets-equivalent.
- `buildDeposit` for a wallet with no allowance returns an approve `pending_sign` (Step 1 of 2).
- `buildQueueWithdrawal` for a wallet with no shares returns `NO_POSITION`.

## Step 3 — Live RPC wiring

Maple's writes are not testable read-only (deposit/redeem are state-changing), but the RPC reads (Steps 2's `getPool` and `getPosition` calls) ARE live reads against Ethereum mainnet. If those return expected shapes, the wiring is validated.

For broader confidence, compare `getPool.data.totalAssets` against the Syrup UI (https://syrup.fi) for a snapshot match.

## Step 4 — A1-A8 regression

```bash
cd ~/.claude/skills/maple-onchainos
# (uses the same A1-A8 block defined by the scaffold v1.6 self-check)
```

Phase 0: version consistency
Phase 1: SKILL.md ↔ exports ↔ --help cross-check
Phase 2: read-only output shape
Phase 3: idempotency (repeat read calls deterministic)
Phase 5: validators
A6: SKILL.md/package.json version sync
A7: every parseUnits decimals param validated upstream (n/a — pool registry supplies decimals; no user-passed decimals)
A8: nativeBalanceCheck wired for non-zero tx.value tools (passes for deposit/withdrawal even though both have value=0, since helper is imported)

## Step 5 — Live broadcast (OPTIONAL)

**Skill:** `test-plugin --live`

### Prerequisites
- Onchainos wallet logged in
- USDC on the chosen chain (≥ 1 USDC for a meaningful test on mainnet given pool min)
- Native gas (~$5 of ETH for mainnet; Base is much cheaper)
- User has EXPLICITLY OPTED IN

### What it does

For a 1 USDC deposit:

1. Pre-flight: record USDC balance + pool exchange rate
2. Call `buildDeposit` → if allowance insufficient, receive approve `pending_sign`
3. Broadcast approve via `onchainos wallet contract-call`
4. Poll for approve confirmation
5. Re-call `buildDeposit` → receive deposit `pending_sign`
6. Broadcast deposit tx
7. Poll `getPosition` until shares appear (~1 block)
8. Report: tx hashes, fee paid, shares received, assets-equivalent

For a withdrawal (optional reverse step):

1. Call `buildQueueWithdrawal`
2. Broadcast — receives requestRedeem tx
3. Note: assets do NOT arrive immediately — withdrawal manager processes in cycles

### Broadcast pattern

```bash
onchainos wallet contract-call \
--chain <chain> \
--to <unsigned_tx.to> \
--input-data <unsigned_tx.data> \
--amt <unsigned_tx.value> \
--biz-type defi \
--strategy maple-onchainos \
--force
```

## Skipping live tests

If a funded wallet is unavailable or the developer doesn't want to spend real funds, **stop at Step 4**. Live tests are optional.

## When all 5 steps pass

Production-ready. Record live tx hashes in the SKILL.md's Migration note for audit traceability.
71 changes: 71 additions & 0 deletions skills/maple-onchainos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# maple-onchainos

OnchainOS-routed Maple Finance / Syrup integration. Lend USDC/USDT into Maple's ERC-4626 pools (syrupUSDC, syrupUSDT) and queue withdrawals. EVM only (Ethereum mainnet + Base).

The skill reuses the calldata semantics from `maple-labs/maple-js` (the official Maple SDK) — `poolDeposit` maps to ERC-4626 `deposit(assets, receiver)`, `poolQueueWithdrawal` maps to `requestRedeem(shares, owner)` — but skips the SDK's provider-dependent gas estimation and local-signing helpers. Onchain OS handles those.

## Install / wire

This skill installs into `~/.claude/skills/maple-onchainos/` and is picked up automatically by Claude Code.

```
~/.claude/skills/maple-onchainos/
├── SKILL.md # AI guidance + Command Index + routing map
├── README.md # this file
├── FILL-IN.md # per-tool implementation checklist
├── QA-PIPELINE.md # explore-plugin + test-plugin walkthrough
├── package.json
├── tsconfig.json
├── cli.ts # dispatcher (tsx cli.ts <tool> '<json>')
├── runtime.ts # viem clients, pool registry, ABI fragments
└── index.ts # 5 tools
```

## Example user prompt

> "Lend 100 USDC into Maple on Ethereum."

The agent will:

1. Call `buildDeposit` with `chain=ethereum`, `poolAddress=0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b` (syrupUSDC), `amount=100`, `walletAddress=...`.
2. Receive Step-1-of-2 approve `pending_sign`, broadcast via `onchainos wallet contract-call`.
3. Re-invoke `buildDeposit` with the same params, receive the deposit `pending_sign`, broadcast.
4. (Optional) Call `getPosition` to confirm the shares balance.

## Tools

| Tool | Returns | Calls |
|---|---|---|
| `listSupportedPools` | `{status:'ok', data}` | static pool registry |
| `getPool` | `{status:'ok', data}` | viem ERC-4626 reads |
| `getPosition` | `{status:'ok', data}` | viem ERC-20 / ERC-4626 reads |
| `buildDeposit` | `pending_sign \| ToolError` | viem encodeFunctionData → `deposit(uint256,address)` |
| `buildQueueWithdrawal` | `pending_sign \| ToolError` | viem encodeFunctionData → `requestRedeem(uint256,address)` |

## CLI smoke tests

```bash
cd ~/.claude/skills/maple-onchainos
tsx cli.ts --help
tsx cli.ts listSupportedPools '{}'
tsx cli.ts getPool '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b"}'
tsx cli.ts getPosition '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b","walletAddress":"<your-wallet>"}'
tsx cli.ts buildDeposit '{"chain":"ethereum","poolAddress":"0x80ac24aa929eaf5013f6436cda2a7ba190f5cc0b","amount":"10","walletAddress":"<your-wallet>"}'
```

## Live broadcast

```bash
onchainos wallet contract-call \
--chain <chain> \
--to <unsigned_tx.to> \
--input-data <unsigned_tx.data> \
--amt <unsigned_tx.value> \
--biz-type defi \
--strategy maple-onchainos \
--force
```

## Provenance

Form A skill scaffolded from `maple-labs/maple-js` (TypeScript SDK, not a skill — built from scratch wrapping the SDK's calldata semantics) using the OnchainOS DApp scaffold v1.6 (incorporates P1-14/15/16 patterns: native-balance pre-flight, mandatory `validateDecimals`, fee-mutation flag docs).
Loading