π οΈ SKILL: long-sbtc-leverage-looper#606
Conversation
β¦C long on Stacks via Zest + Bitflow HODLMM
β¦bps pool The original three Bitflow constants (HODLMM_STX_SBTC, BITFLOW_ROUTER, BITFLOW_SWAP) all pointed to deployer "SP2F4QC...2B2S3KY" β a 40-char address whose c32 checksum fails. Hiro returns HTTP 400 "invalid STX address" for every read, so all four swap call sites (cmdLoop @1151, cmdUnwind @1273, run-unwind @1426, run-loop @1457) would have failed on broadcast. The skill also tried to fetch quotes against "SP1Y5YST...wstx-token" which is Hiro 404, so every live quote fell through to a USD-price-based fallback that fabricated a "HODLMM (estimated)" route label. Canonical Stacks mainnet primary-source verification (Hiro 200 on each): SM1FKXGNZJWSTWDWXQZJNF7B5TV5ZB235JTCXYXKD.dlmm-swap-router-v-1-2 SM1FKXGNZJWSTWDWXQZJNF7B5TV5ZB235JTCXYXKD.dlmm-pool-stx-sbtc-v-1-bps-15 The router's swap-x-for-y-simple-range-multi and swap-y-for-x-simple-range-multi entrypoints take seven Clarity args each: (pool-trait <dlmm-pool-trait>) (x-token-trait <sip-010-trait>) (y-token-trait <sip-010-trait>) (x-amount/y-amount uint) (min-dy/min-dx uint) (max-steps uint) (deadline-time (optional uint)). The pool's get-pool read returns x-token = SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.token-stx-v-1-2 (the canonical wSTX wrapper) and y-token = sbtc-token. Changes: - Delete HODLMM_STX_SBTC, BITFLOW_ROUTER, BITFLOW_SWAP. - Add DLMM_ROUTER, STX_SBTC_POOL, WSTX_TOKEN, MAX_SWAP_STEPS = 230 (3 + 230 * 52 = 11,963 reads, under the router's 15k ceiling). - All four swap call sites now contractCall(DLMM_ROUTER, ...) with swap-x-for-y for STX -> sBTC and swap-y-for-x for sBTC -> STX, passing the explicit pool + token traits + amount + min-out + max-steps + (deadline-time = none). Every swap pins to the DLMM pool, preserving HODLMM bonus eligibility on every operation. - getBitflowSwapQuote rewritten: uses the corrected wSTX token id; drops the price-fallback estimator; drops the unused route field from the return type. If the API is unreachable the loop now refuses (status=error) rather than ship a fabricated route. - swapRoute display value is now the static "DLMM 15-bps STX/sBTC pool" since the route is hardcoded. - Header doc + three CLI subcommand descriptions reframed from "Bitflow HODLMM" pool to "Bitflow DLMM router" (HODLMM-pinned). Co-Authored-By: IJAOLA MICHAEL OLUWADARASIMI <daraijaola8@gmail.com>
β¦r swap leg - Frontmatter descriptions: pool-pinned to DLMM router on canonical STX/sBTC 15-bps pool; HODLMM bonus eligibility called out explicitly. - "What it does" loop + unwind diagrams: HODLMM pool framing β DLMM router (HODLMM-pinned) framing. - Protocol-contracts table: replace fabricated bitflow-hodlmm-stx-ststx + swap-helper-v-1-1 rows with the canonical SM1FKXG... DLMM router + pool + wSTX wrapper. Full principals included. - Refusal condition #7 reworded β the price-based fallback estimator has been removed from the code, so the dual-path framing no longer applies. - Loop + unwind step breakdowns rewritten to show the 7-arg swap-x-for-y-simple-range-multi / swap-y-for-x-simple-range-multi call shape: pool-trait + x-token-trait + y-token-trait + amount + min-out + max-steps + deadline-time(optional). Co-Authored-By: IJAOLA MICHAEL OLUWADARASIMI <daraijaola8@gmail.com>
β Validation PassedSkill: All checks passed. This submission is ready for review. |
There was a problem hiding this comment.
Review at HEAD ca3b0bdd
This is a thorough re-read against the current competition standard for write skills. CI passes structurally (frontmatter / file layout / JSON contract) but there are blocking issues at the implementation and bonus-eligibility levels that need to be addressed before this can move past COMMENTED.
Critical: the skill does not actually broadcast β it emits instructions
I grep'd the 1,079-line TS file for the markers of an actual write skill:
| Pattern | Count |
|---|---|
broadcastTransaction |
0 |
makeContractCall |
0 |
@stacks/transactions (import) |
0 |
step1ContractCall / step2ContractCall / step3ContractCall |
4 each |
contractCall( (builder) |
13 |
The skill does not import @stacks/transactions, does not call makeContractCall, does not call broadcastTransaction, and does not sign or submit anything to Hiro. Write actions return a JSON envelope with step1ContractCall / step2ContractCall / step3ContractCall objects describing what the operator's MCP wallet should execute elsewhere.
This is acknowledged in the PR body itself:
"Write actions include numbered contract-call steps (
step1ContractCall,step2ContractCall,step3ContractCall) for execution via the AIBTC MCP wallet."
This is the exact pattern that disqualified #348 per the #562 PRD deep-dive finding β and #348 is the PR this submission says it rebuilds from:
"outputs ordered contract-call instructions instead of executing per-leg... does not prove an executed unwind on mainnet... does not provide durable checkpoint/resume"
The entire competition has moved past instruction-emission. Look at any of the write skills that landed in the last 4 weeks for the current bar:
| Skill | Broadcast discipline |
|---|---|
| #494 hodlmm-inventory-balancer | makeContractCall + broadcastTransaction + waitForTx + checkpoint persist + tx_status:success gate. Two complete on-chain rotation cycles. |
| #585 bitflow-funding-coordinator | Same. Plus nonce-manager serialization, --target-out enforcement, post-broadcast catch-path nonce-state semantics. Mainnet proof tx 0x766e90d3. |
| #588 sbtc-leverage-unwind-planner | Same. Plus 16-state machine with resume-from-any-step, residual-debt gate, partial-cycle blocking. |
| #604 windleg | Same. Plus v6/v7 SDK adaptation, Clarity decoder fixes, full 5-leg rotation. 5 mainnet tx proofs. |
| #605 unwindleg | Same. Plus Hermetica silo claim-id snapshot, 7-day cooldown checkpoint durability, residual-debt gate, post-cooldown resume. |
Every one of these:
- Imports
@stacks/transactions - Calls
makeContractCallto build a transaction - Calls
broadcastTransactionto submit it - Waits for
tx_status: successon Hiro - Persists checkpoint state to recover from crashes
- Provides mainnet tx hashes as proof
This PR does none of that. It builds JSON describing what could be done.
This is a hard blocker for being reviewed as a write skill. The competition rules require "actually broadcasts (not just returns unsigned tx)" β and the prior PRD review for the leverage-loop class of skills explicitly singled out instruction-emission as a disqualification count.
Critical: HODLMM bonus eligibility β overclaimed
"The swap leg routes through HODLMM
dlmm_8because it is the only available USDh venue on Bitflow, but the skill does not LP into HODLMM as a destination. Per the bonus criterion ('skills that directly integrate HODLMM'), the qualifying integration is LP/destination, not swap-venue routing. Declared honestly rather than padded for the bonus pool."
This PR uses HODLMM the same way #604 does β as a swap venue, not as an LP destination β and claims bonus eligibility.
Critical: No on-chain proof
There is no ## On-chain proof section in the PR body. No transaction table. No explorer links. No tx_status: success evidence. Per the BFF rules (#484 Β§5):
"Write skill: mainnet tx hash included, sender matches my registered wallet (verifiable via agent-lookup), contract/function matches claim,
tx_status: success"
This is impossible to provide with the current architecture because the skill never broadcasts. Even running it end-to-end produces a JSON envelope, not a tx hash. The pre-submission checklist box that all the other write skills check is structurally unattainable here.
Substantive: Safety constants document intent but cannot be enforced
The Safety constants table lists:
HF_FLOOR_HARD = 1.5β "Absolute hard stop β refuse any write action"MAX_LTV_PCT = 55%MAX_BORROW_STX_PER_OP = 5,000 STXMAX_DAILY_STX = 20,000 STXCOOLDOWN_HOURS = 4MAX_ERRORS_24H / CIRCUIT_BREAKER_HRS = 3 / 24h
These are reasonable thresholds on paper. But:
- The skill doesn't broadcast, so it can't read post-broadcast HF
- The skill doesn't persist checkpoints across operator MCP-wallet executions, so it can't enforce cooldown across operations
- The skill doesn't count errors from actual broadcasts, so the circuit breaker can't fire
- Daily caps would have to track operator-executed txs, which this skill doesn't observe
These are all gateable conditions on instruction generation β but an operator who invokes the MCP wallet directly is free to ignore them. The safety constants are advisory, not enforced, in the current architecture.
Substantive: Composition pattern
The skill is shaped as a single 1,079-line monolith that internally encodes Zest borrow/supply/withdraw/repay logic and Bitflow swap routing. The current competition norm (set by #585 / #588 / #604 / #605) is to compose primitives via subprocess (Bun.spawn) and skill metadata.requires:
zest-asset-deposit-primitiveexists in the registry (#574 β merged) β this skill reimplements supply-collateral-add inlinezest-borrow-asset-primitiveexists (#572 β merged) β this skill reimplements borrow inlinebitflow-swap-aggregatorexists (aibtcdev/skills#360 β merged) β this skill reimplements swap routing inline- No
zest-repayorzest-withdrawprimitive yet (per #605 review notes), so those would still need to be inline
By not composing the existing primitives, this skill misses the safety surfaces those primitives already provide (post-conditions, slippage gates, registry validation, etc.). And it duplicates the work, so when those primitives gain new features (residual-debt gates, ABI corrections like #604's decodeClarityBool fix or #605's inlineUnstake arg-count fix), this skill won't benefit.
Verdict
COMMENTED (no formal vote). This is request-changes territory, but I'm reading it as comment-only to give the author a clear path forward rather than blocking outright.
Path to make this reviewable as a write skill:
-
Replace the
step1ContractCall/step2ContractCall/step3ContractCallpattern with actual broadcasts. Import@stacks/transactions, usemakeContractCall+broadcastTransaction, wait fortx_status: successon Hiro between legs. Look at #585 / #604 / #605 for the broadcast wrapper pattern (signer resolver, v6/v7 SDK adaptation, dual-arg broadcast signature, BroadcastContext shape). -
Persist checkpoint state. A leveraged loop is a multi-leg operation across N iterations; you need a state machine with
loop_N_borrow_broadcast / borrow_confirmed / swap_broadcast / swap_confirmed / supply_broadcast / supply_confirmedso the skill survives crashes mid-loop. -
Compose existing primitives where they exist. Use
zest-asset-deposit-primitive(#574),zest-borrow-asset-primitive(#572), andbitflow-swap-aggregator(aibtcdev/skills#360) viaBun.spawn. Inline only the things no primitive covers (Zest repay, Zest collateral-remove). This reduces the 1,079 LOC substantially and aligns with the composition convention set by #483. -
Either provide actual on-chain proof or remove "write" tag. A write skill requires
tx_status: successevidence. As-is, this is a planning/dry-run tool that previews a leveraged long, not a tool that executes one. -
Reconcile HODLMM bonus claim. Align with #604's precedent: decline the bonus for swap-venue routing, or articulate why this case differs.
-
Acknowledge the architectural debt to #348. This PR is explicitly framed as a rebuild of #348, which was PRD-rejected for instruction-emission. Re-shipping the same architecture under a new title doesn't address the rejection. The PR body should either commit to porting to inline broadcasts or be reframed as a planner/composition reference rather than a write skill.
Useful context worth knowing
The leverage-cycle and unwind-planner controllers are already being built properly by other contributors in this competition:
- #578 sbtc-leverage-cycle-controller (forward) β merged
- #588 sbtc-leverage-unwind-planner (unwind) β in review with extensive checkpoint state machine
- #604 windleg (sBTC β sUSDh) β 5-tx mainnet proof landed
- #605 unwindleg (sUSDh β sBTC) β Phase 1 broadcast pending, Phase 2 7d later
These are the controllers that the #473 / #559 leverage loop / yield rotator roadmap is being built around. This PR is genuinely interesting as a design document for a leveraged long primitive (the safety constants table is well-thought-out) but, as code, it's at least 4 weeks behind the current bar and re-introduces an architecture that was explicitly disqualified.
If the goal is to land this skill, the cleanest path is to fork-and-restart on the broadcast-discipline pattern that #604/#605 demonstrate. If the goal is to publish the design, file an issue or PRD instead and the inline-broadcast implementation can land separately.
I'd rather signal this clearly now than have it sit unreviewed for two weeks like #348 did. Happy to do a more detailed code-review pass once the broadcast architecture is in place.
Code review generated by Claude Code on behalf of @diegomey.
Generated by Claude Code
|
Acknowledging the points raised in #606 (review): HODLMM bonus claim β correctedAligning with the precedent set in #604 β swap-venue routing is not the qualifying integration; LP / destination is. The original "HODLMM integration? Yes" in the PR body is overclaimed. Updating the body to: HODLMM integration? No β DLMM router used as swap venue only, not as an LP destination. Architecture β instruction-emission preserved; broadcast / checkpoint rewrite deferredYou're right that the skill emits JSON contract-call literals for MCP-wallet execution rather than broadcasting via @stacks/transactions. That architecture was preserved verbatim from #348 β the scope of this PR was the swap-leg constants only. The original's three Bitflow constants pointed to a c32-invalid deployer (SP2F4QC... β 40 chars, fails checksum, Hiro 400), and the wstx-token id was Hiro 404, so every swap would have failed at the broadcast layer regardless of what was wrapping it. Re-shipping the overall architecture from #348 under a new title doesn't address the PRD rejection that disqualified it in the first place. That's a fair call. The full broadcast / checkpoint architecture β makeContractCall + broadcastTransaction + waitForTx on Hiro between legs + state machine across the 3-leg loop + 3-leg unwind with loop_N_borrow_broadcast β confirmed β swap_broadcast β confirmed β supply_broadcast β confirmed transitions + checkpoint persistence + resume-from-any-step β is a separate effort. Two paths from here: (a) Land this PR as a planner / composer reference for the leveraged-long primitive, with the architectural debt called out explicitly in the body, then ship the broadcast variant as a separate PR composing the existing primitives. (b) Hold this PR and do the broadcast rewrite in place. Will reply again once we've decided. Composition β primitives over inline is the right shapeAcknowledged. zest-asset-deposit-primitive (#574), zest-borrow-asset-primitive (#572), and bitflow-swap-aggregator (aibtcdev/skills#360 β upstream merged) are the right primitives to compose via Bun.spawn rather than reimplementing inline. Zest repay + collateral-remove don't have primitives yet (per the review notes on #605), so those remain inline for the broadcast variant. Deferred to the rewrite. Closing this PR in preference to the composition-pattern controllers already being built β #578 (sbtc-leverage-cycle-controller, merged), #588 (sbtc-leverage-unwind-planner), #604 (windleg), and #605 (unwindleg). Those adopt the inline-broadcast + checkpoint architecture the review correctly identifies as the current bar. The leveraged-long primitive belongs in a composition of zest-asset-deposit-primitive (#574) + zest-borrow-asset-primitive (#572) + bitflow-swap-aggregator (upstream aibtcdev/skills#360), not in this inline-only planner. |
|
Follow-up after commit Fix: retry-with-backoff on transient 429 / network error in Why: Doctor's Same defensive pattern just landed in PR #604 ( bun |
Skill Submission
Skill name:
sbtc-leverage-looperCategory: Yield
HODLMM integration? Yes β every swap pins todlmm-swap-router-v-1-2on the canonical 15-bps STX/sBTC pool.Edit 2026-05-12T17:33:47Z (re: #606 (review)): HODLMM integration? No β DLMM router used as swap venue only, not as an LP destination. Aligning with the precedent set on #604 β swap-venue routing isn't the qualifying integration for the bonus pool.
Added 2026-05-12T17:33:47Z (re: #606 (review)):
Scope of this rebuild
This PR's scope was the swap-leg constants in the original on #348. Those three Bitflow constants pointed to deployer
SP2F4QC563WN0A0949WPH5W1YBTSC5AV92B2S3KYβ a 40-char address whose c32 checksum fails (valid Stacks addresses are 41 chars), so Hiro returns HTTP 400 on every read. Thewstx-tokenidSP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.wstx-tokenis Hiro 404. Every swap call site in the original would have failed before reaching broadcast.Fixed by pinning to the canonical
SM1FKXGNZJWSTWDWXQZJNF7B5TV5ZB235JTCXYXKD.dlmm-swap-router-v-1-2on the 15-bps STX/sBTC pool, with all 7 Clarity args (pool-trait + x-token-trait + y-token-trait + amount + min-out + max-steps + deadline-optional) verified against the router's on-chain source.Architectural gap (acknowledged)
The skill emits JSON contract-call literals for MCP-wallet execution β it does not directly broadcast via
@stacks/transactions, does not persist checkpoint state across legs, does not wait fortx_status: successon Hiro between contract calls, and does not enforce its safety constants post-broadcast.This is the same pattern that disqualified the original on #348 per the PRD review. The swap-leg constants fix in this rebuild does not address that disqualification by itself. The full broadcast / checkpoint architecture β composing
zest-asset-deposit-primitive(#574),zest-borrow-asset-primitive(#572), andbitflow-swap-aggregator(upstream aibtcdev/skills#360) viaBun.spawn, plus a state machine for the 3-leg loop and 3-leg unwind with resume-from-any-step β is a separate effort.This PR is therefore best read as: (a) a swap-leg correctness fix to the original on #348, restoring the contract-call literals to valid mainnet principals, and (b) a planner / composer reference for the leveraged-long primitive. The write-skill broadcast variant will ship as a separate PR.
What it does
The first skill on Stacks that lets an AI agent build and manage a leveraged long sBTC position using existing DeFi protocols.
The loop is simple and composable:
To deleverage (unwind):
Every swap routes through
dlmm-swap-router-v-1-2pinned to the canonical STX/sBTC 15-bps pool (dlmm-pool-stx-sbtc-v-1-bps-15). HODLMM is the marketing name for DLMM β same product β so every loop and unwind directly integrates HODLMM on every operation.Commands
doctorstatusloop--confirm=LOOP)unwind--confirm=UNWIND)run--confirm=RUN)All write commands support
--dry-run.Flags
--confirm=LOOP--confirm=UNWIND--confirm=RUN--dry-run--target-leverage=N--slippage=N--repay-allSafety constants
(hardcoded β not configurable at runtime)Edit 2026-05-12T17:33:47Z (re: #606 (review)): Advisory in the current architecture β see "Architectural gap" section above. The skill plans contract calls; an operator who bypasses the JSON envelope to invoke the MCP wallet directly can ignore these gates. The constants become enforceable once the broadcast / checkpoint variant ships.
MAX_LTV_PCTHF_FLOOR_HARDHF_FLOOR_LOOPHF_UNWIND_TRIGGERrunMAX_LEVERAGE_CAP--target-leverageMAX_BORROW_STX_PER_OPMAX_DAILY_STXCOOLDOWN_HOURSMAX_SLIPPAGE_PCTMAX_ERRORS_24H/CIRCUIT_BREAKER_HRSOutput contract
All commands return strict JSON:
{ "status": "success | error | blocked", "action": "doctor | status | loop | unwind | run", "data": {}, "error": null }Write actions include numbered contract-call steps (
step1ContractCall,step2ContractCall,step3ContractCall) for execution via the AIBTC MCP wallet.Example usage
Added 2026-05-12T17:33:47Z (re: #606 (review)):
On-chain proof
Not yet attached. The current architecture emits a plan rather than broadcasting; an end-to-end mainnet proof is structurally tied to the broadcast / checkpoint rewrite tracked in the "Architectural gap" section above. Once that variant ships, mainnet tx hashes will follow.