Skip to content

Add DeFi skill index and Blend v2 lending/backstop playbook#55

Open
aristidesstaffieri wants to merge 6 commits into
feat/wallet-skills-clifrom
feat/defi-blend-skill
Open

Add DeFi skill index and Blend v2 lending/backstop playbook#55
aristidesstaffieri wants to merge 6 commits into
feat/wallet-skills-clifrom
feat/defi-blend-skill

Conversation

@aristidesstaffieri

@aristidesstaffieri aristidesstaffieri commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the first DeFi protocol playbook: a Blend v2 skill that maps every core Blend operation — supply, borrow, repay, withdraw, backstop deposit/Q4W, emissions, and projected earnings — to concrete stellar contract invoke commands, plus a thin defi index skill that routes protocol tasks and defines the division of labor with the wallet skill (protocol knowledge here; keys, signing, and submission there).

Every documented command was exercised end-to-end on testnet against the deployed v2 contracts: the full lending lifecycle (including over-repay refunds and batched submits), the backstop deposit → queue → dequeue lifecycle with the 17-day timelock, emissions reads and claim previews via simulation, and the bundled APR-ranking script. Mainnet addresses are cross-checked against the blend-utils registry and the Blend docs deployment list. The legacy v1 deployment is explicitly out of scope.

What's in this PR

  • skills/defi/SKILL.md — new DeFi index skill; routes protocol tasks to per-protocol playbooks
  • skills/defi/blend/SKILL.md — Blend v2 overview: architecture, v2 mainnet/testnet contract references, deriving all other addresses on-chain
  • skills/defi/blend/lending.md — the submit model and RequestType table, supply/borrow/repay/withdraw, pool discovery, state reads, emissions check/claim, projected-earnings math
  • skills/defi/blend/backstop.md — LP-token minting, deposit, Q4W lifecycle, auto-compounding claim, backstop APR methodology
  • skills/defi/blend/scripts/rank-backstops.sh — executable scaffold that ranks reward-zone pools by approximate backstop APR, RPC only
  • site/src/data/skills.ts, site/src/app/styles.scss — DeFi filter and skill card for skills.stellar.org

Test plan

  • All lending commands run on testnet against the deployed v2 pool (supply, borrow, over-repay refund, withdraw, batched submit)
  • Full backstop lifecycle on testnet: single-sided Comet LP join, deposit, queue (17-day exp confirmed), premature-withdraw rejection, dequeue, claim preview
  • Emissions getters, claim simulation, Comet spot-price and oracle lastprice reads verified on testnet
  • scripts/rank-backstops.sh run against the testnet backstop (both reward-zone pools ranked)
  • Mainnet addresses cross-checked against blend-utils mainnet.contracts.json and docs.blend.capital
  • CI green
  • Site skill card renders correctly

Companion PRs

aristidesstaffieri and others added 5 commits July 8, 2026 13:06
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a DeFi skill package with the Blend lending playbook, closing the
Blend portion of the Agentic Wallet CLI epic (stellar/stellar-cli#2625,
#2628). Composes the wallet skill for keys/signing/submission.

- skills/defi/SKILL.md: DeFi index/router; draws the wallet-primitives vs
  protocol-logic boundary and resolves the wallet skill's ../defi/ link
- skills/defi/blend/SKILL.md: architecture, mainnet/testnet contract refs
  (3 registry-authoritative addresses; the rest derived on-chain via RPC),
  routing, and dependency/[VERIFY] notes
- skills/defi/blend/lending.md: the Pool `submit` model + RequestType table,
  supply/borrow/repay/withdraw examples, pool discovery, reading state
- skills/defi/blend/backstop.md: deposit/Q4W/withdraw/claim and an RPC-only
  "rank backstops by APR" script

Wire the site: new "DeFi" filter category, a SKILL_CARD_SOURCES entry, and
the styles.scss filter whitelist so the card renders.

All dynamic-data scripts use RPC only (no indexer). Written from Blend's
contract architecture; signatures, RequestType numbering, the Q4W timelock,
and the emission split are flagged [VERIFY] against blend-contracts source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
  Target the skill exclusively at the Blend v2 deployment and correct
  everything that live testing against the deployed contracts surfaced:

  - Replace mainnet contract references with the v2 pool factory,
    backstop, and emitter addresses; document the v2 testnet deployment
    and warn about the coexisting v1 deployment
  - Match all signatures, getters, arg names, and struct shapes to the
    deployed v2 ABI (pool_data, user_balance, get_positions, backstop
    claim with min_lp_tokens_out and auto-compounding, 17-day Q4W)
  - Add emissions coverage: reserve_token_id layout, accrued-emissions
    getters, claim preview via simulation, and a projected-earnings
    section for supply interest and BLND emissions with correct scaling
  - Add tested recipes for pricing BLND via the Comet LP, pricing
    reserve assets via the pool oracle, and minting backstop LP tokens
    with a single-sided Comet join
  - Require --source on read commands (stellar-cli needs a source
    account to simulate) and note trustline requirements for borrowing
  - Extract rank-backstops.sh into scripts/ as an executable utility
    and add tables of contents to both reference files

  All commands exercised end-to-end on testnet: supply, borrow, repay
  with refund, withdraw, batched submit, emissions reads, and the full
  backstop deposit/queue/dequeue lifecycle.
@aristidesstaffieri aristidesstaffieri self-assigned this Jul 10, 2026
@aristidesstaffieri aristidesstaffieri changed the title Feat/defi blend skill Add DeFi skill index and Blend v2 lending/backstop playbook Jul 10, 2026
@oceans404

Copy link
Copy Markdown
Contributor

I stress tested this the same way as #49: used Fable to spin up separate fresh subagents with no Stellar or Blend context, given only this branch's skill files and --help, CLI 26.0.0. Six agents on testnet, then two on mainnet with real funds, every write human-approved. Then we ran two more mainnet agents with a one-page errata sheet covering everything the first round hit, to check whether those fixes are actually enough. Whole thing cost 0.44 XLM, all fees.

Short version: the protocol content is right. Every command shape, request type, error code, and state read matched reality on both networks, and the submit section is the best-written part of either PR. But agents only finished their tasks by leaving the docs, and twice a "read-only" operation tried to submit a real transaction. Ranked by what it cost them:

  1. Repay can't close a loan as written. "Pass an amount larger than the debt" is impossible when all you hold is the loan proceeds: dTokens round up at borrow, so debt > principal from the same ledger (we measured 8 stroops over within minutes, on mainnet). Pass more than you hold → #10 (the pool pulls the full amount before refunding). Pass exactly your balance → dust debt survives and blocks withdraw-all with #1205. Three agents hit this; all three escaped the same undocumented way, buying a small buffer via a DEX path payment. Repay needs a "fully closing a position" note: get a buffer of the borrowed asset first, then any amount between debt and balance works and the refund comes back exact.
  2. Reads aren't always read-only. Against TTL-archived state (an abandoned reward-zone pool, and separately a dead pool's oracle) a plain getter skips simulation and auto-submits a RestoreFootprint tx, no --send=yes involved. Two agents triggered this on mainnet (neither landed, fees zero, but that was luck and low balances). The docs say "reads simulate; nothing is signed or submitted" in three places. Caveat it, name archived state as the cause of surprise Account not found errors on reads, and have examples pass --send=no.
  3. Mainnet doesn't work from the docs. The CLI's built-in mainnet network is a BYO-RPC placeholder, every example here sets NETWORK=mainnet, and no skill in the repo gives an endpoint (all of them link out to the providers page, which an agent working from the skill can't act on). Both mainnet agents died on their first command and needed a human to hand them a URL. Suggested home: skills/standards/SKILL.md already catalogs ecosystem infra (indexers, oracles, wallets), so a short mainnet RPC providers list belongs there, with the wallet/blend/data skills pointing at it next to their network add examples.
  4. min_collateral blocks every small borrower and appears nowhere. All the usable reward-zone pools set a $5 floor (in the oracle's base-asset decimals), and it's checked against the c_factor-adjusted collateral value, not raw. With XLM at 0.75 that's ~35 XLM of collateral before you can borrow a cent. The error is #1224, also absent from the docs. We got this wrong ourselves on the first pass (assumed raw value), so it's worth stating precisely.
  5. Examples hardcode mainnet, which is the network that doesn't work out of the box. backstop.md and the derivation block paste mainnet literals; testnet addresses live only in the SKILL.md table. Agents had to hand-swap both the env var and the addresses, and one nearly ran a mainnet literal against testnet.
  6. Pool discovery. The documented method (factory getEvents) can't work: RPC keeps ~7 days of events and the deploys are older, so it returns nothing. The method that works, reward_zone() on the backstop, is never named in prose; agents found it by reading rank-backstops.sh's source. There's also no ready-to-paste testnet pool address anywhere.
  7. rank-backstops.sh fails silently off-mainnet. NETWORK=testnet SOURCE=alice ./rank-backstops.sh prints nothing, not even the CSV header: mainnet BACKSTOP default + 2>/dev/null + set -e eat the error. And finishing the script's step 4 isn't possible from the docs, because
  8. the borrow-rate formula isn't in the docs. Projected earnings and backstop APR both need it, and lending.md points at interest.rs. ir_mod's scale and bounds, the status enum values, q4w_pct's scale, and get_tokens ordering are also undefined. Each one cost an agent a detour, and the APR/earnings workflows (the headline deliverables) couldn't be completed from the docs alone.
  9. Claiming emissions needs a BLND trustline first. Even the simulated claim preview reverts with #13 without it. One prerequisite line fixes it (derive BLND via backstop_tokenget_tokens, change-trust).
  10. There's no way to get assets. Every flow assumes a USDC/BLND balance. Friendbot is XLM-only, mint is issuer-gated (we checked), token lists only identify assets. Agents self-rescued two ways, neither documented: borrow the asset against XLM collateral (backstop.md never links lending.md for this, and it's the only way to fund a backstop from XLM), or DEX path payments. Also: testnet has two different "USDC"s across the two pools, one with zero DEX liquidity. Worth telling readers to check name() before assuming which USDC they have.
  11. Grab bag: tx new ops take no --send flag (they submit by default; the --send=yes convention is invoke-only and the docs never distinguish); reads without --network silently query the wrong network and a funded account looks empty; --fee is deprecated for --inclusion-fee; --id native doesn't work with contract invoke (need contract id asset first, which nothing points to); there's no remediation for transaction submission timeout (public RPCs drop low-fee Soroban txs under surge; bumping --inclusion-fee fixes it, and until #2623 that's the only answer); the drain story doesn't cover dust the destination can't hold (convert via DEX first) or dust with no market (SAC burn); Soroban pool writes run ~0.09 XLM each in resource fees, which surprised every agent.

For the second round we gave two fresh mainnet agents the docs plus this errata sheet, verbatim:

  1. stellar network add mainnet --rpc-url <endpoint> --network-passphrase "Public Global Stellar Network ; September 2015" (the built-in alias has no RPC).
  2. stellar token doesn't exist yet (#2620), so use stellar contract invoke --id <TOKEN> -- balance/transfer/name/decimals.
  3. No structured errors yet (#2622): failures are HostError: Error(Contract, #NNNN). Codes seen: #1205 health violation (over-borrow or withdraw with debt, incl. dust), #1001 Q4W timelocked, #10 repay pulling more than you hold, #13 missing trustline, #1224 below min_collateral.
  4. Full repay needs a ~5-10% buffer of the exact borrowed asset (check the issuer via name()); get it via tx new path-payment-strict-receive; then repay any amount between debt and balance, excess refunds.
  5. BLND trustline before any claim, even simulated.
  6. Enumerate pools with reward_zone() on the backstop.
  7. contract invoke needs --send=yes to submit; tx new submits by default, no --send flag.
  8. Unexpected Account not found on a read = probably archived state; stop, don't retry (the retry is what submits a restore).
  9. Most reads work with an unfunded source; funding matters only for submits.
  10. min_collateral (~$5, oracle base decimals) is checked against c_factor-adjusted collateral: XLM at 0.75 needs ~35 XLM before any borrow. Error: #1224.
  11. Pass --send=no on every read.
  12. On transaction submission timeout: verify it didn't land (tx fetch result, seq unchanged), then retry with --inclusion-fee 1000000.

With that sheet, both agents ran clean: no human interventions on setup, the full real lifecycle completed (35.5 XLM supplied, 1 USDC borrowed, emissions claimed for real (7980 stroops claimed vs 7955 previewed), repaid via the buffer, withdrawn, account drained to the stroop), and the yield-analysis task that no docs-only agent could finish came back with a justified pool choice and an on-chain APY breakdown. Confusion events went from 5+ per agent to 3. So I don't think this PR needs restructuring, it needs roughly that page folded into the existing files. (Fair warning from our own experience: item 10 above originally said raw oracle value and was wrong. These fixes are worth testing at the boundary, not just writing.)

What held up well: the submit recipes (supply/borrow/repay/withdraw/batching) are copy-paste correct; the backstop Q4W lifecycle matches reality exactly (17-day exp, #1001 on early withdraw, dequeue restores shares); the single-sided Comet join works verbatim; the derivation chain worked for every agent on both networks; the emissions stream-id math, the accrued-updates-when-touched caveat, and simulate-claim previews are all accurate; share-to-underlying conversion checks out against real balances; and all ten agents navigated the defi → blend → wallet routing cold. The wallet skill's verify-before-resubmit guidance also quietly saved us twice on mainnet.

Coverage caveat: backstop writes (LP join, deposit, queue/dequeue, early-withdraw rejection) were verified on testnet only, since the 17-day exit lock makes mainnet testing impractical. Not tested anywhere: backstop withdraw after Q4W expiry, backstop auto-compound claim, auction fills (RequestTypes 6-9), submit_with_allowance, flash_loan, relayer flows. Per-agent logs available if useful.

  Addresses the agent stress-test feedback on #55: repay full-close
  recipe (dToken round-up, #10/#1205 failure modes, buffer-first),
  min_collateral semantics (#1224, c_factor-adjusted, oracle decimals),
  --send=no on all reads + archived-state RestoreFootprint caveat,
  reward_zone() as the pool-discovery method (factory events are past
  RPC retention), the borrow-rate curve with exact scales (ir_mod 7dp
  [0.1,10], status enum, q4w_pct 7dp, get_tokens order), BLND trustline
  prerequisite for claims (#13), getting assets from XLM (borrow or
  path payment; two testnet USDCs), tx-new-vs-invoke submit semantics,
  resource-fee and timeout remediation notes, testnet-first env blocks,
  and a verified public mainnet RPC endpoint list in the standards
  skill (the CLI's built-in mainnet alias has no RPC URL).

  rank-backstops.sh now derives the backstop per network and fails
  loudly instead of printing nothing off-mainnet; verified against
  testnet and mainnet.
@aristidesstaffieri

Copy link
Copy Markdown
Collaborator Author

Folded the errata into the existing files in 00d46d1 — no restructuring, as suggested. Per item, with what was re-verified before writing:

  1. Repay full-close — rewrote the Repay section as a "Fully closing a loan" recipe: buffer of the exact borrowed asset first (path payment, name() check), then any amount between debt and balance. Both failure modes are named (#10 when the pull exceeds your balance, #1205 when dust blocks withdraw-all), and the Withdraw section cross-references the dust case.
  2. Reads — every read example in all three files now passes --send=no; the "nothing is signed or submitted" claims are replaced with the archived-state caveat (RestoreFootprint auto-submit, Account not found as the symptom, "don't retry — the retry is what submits the restore").
  3. Mainnet setup — a "Public mainnet RPC endpoints" table is now in standards/SKILL.md with three no-signup endpoints (each probed with getHealth before listing) plus the network add one-liner; the blend skill's new Network setup section links to it and states plainly that the built-in mainnet alias has no RPC URL.
  4. min_collateral — documented in Borrow and in the PoolConfig field list: checked against the c_factor-adjusted collateral value, in the oracle's base asset at the oracle's decimals(), error #1224. Since you flagged the raw-vs-adjusted trap, I verified in source (submit.rs compares collateral_base, the effective value) and on mainnet (the active reward-zone pool returns 500000000000000 = $5 at 14 oracle decimals).
  5. Mainnet literals — examples are testnet-first now; backstop.md and the derivation block use the shared env vars, and mainnet addresses appear only in the reference table and the labeled mainnet block.
  6. Discoveryreward_zone() on the backstop is the named method in prose (ran it on both networks); getEvents is demoted to an explicit "don't" with the retention explanation; a ready-to-paste testnet pool address is included (verified live in the testnet reward zone).
  7. rank-backstops.sh — derives the backstop per network (testnet/mainnet map, BACKSTOP= override), errors go to stderr instead of 2>/dev/null, unknown networks exit 1 with a message. Tested: testnet prints 2 rows (was silent empty), mainnet prints 5, futurenet fails loudly.
  8. Borrow-rate formula — transcribed from interest.rs into lending.md with exact scales, including that the r_three leg is not scaled by ir_mod, and that v2's ir_mod is 7-decimal with [0.1, 10] bounds (the source's own doc comment stale-says 9 decimals; the code uses SCALAR_7). Also defined: the status enum (0–6) and its borrow/supply gating, q4w_pct (7-decimal), exp (unix seconds), get_tokens ordering ([BLND, USDC], verified on-chain). The script's step 4 and backstop.md now reference the formula, so the APR is completable from the docs.
  9. BLND trustline — prerequisite line in SKILL.md and a callout in the emissions section: even the --send=no preview reverts with #13 without it, with the derive-BLND → name()change-trust chain.
  10. Getting assets — new subsection: borrow against XLM collateral or DEX path payment; backstop.md now links lending.md as the way to fund a backstop from XLM. The two testnet USDCs are called out (I confirmed the two pools' USDC reserves have different issuers, GBBD47… vs GATALT…) with the name()-before-assuming rule.
  11. Grab bag — the tx new vs contract invoke submit distinction, the missing---network wrong-chain gotcha, ~0.09 XLM resource fees, and the timeout → tx fetch result--inclusion-fee remediation are all in SKILL.md's Building transactions / Network setup; stellar token mentions are gone; contract id asset --asset native is pointed to. One scope note: the drain-dust gaps are wallet-skill material, so they belong on the feat/wallet-skills-cli branch (Add wallet skill: use the Stellar CLI as a wallet #49) rather than this one.

On the trustline point (errata item 5, "before any claim"): I kept the requirement on the pool-emissions claim only. The backstop claim auto-compounds — BLND moves backstop→Comet without touching the user — and it's on your not-tested list, so I didn't want to document a requirement neither of us has observed. If your logs show #13 on a backstop claim preview too, I'll add it there as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants