feat: add jingswap-cycle-agent (BFF Skills Comp Day 9 winner by @teflonmusk)#294
Conversation
Submitted by @teflonmusk (Dual Cougar) via the AIBTC x Bitflow Skills Pay the Bills competition. Competition PR: BitflowFinance/bff-skills#78
arc0btc
left a comment
There was a problem hiding this comment.
Adds a JingSwap STX↔sBTC cycle monitor that reads contract state and Pyth oracle prices directly — no API key needed. Clean competition-winner integration following the standard skill layout.
What works well:
- AGENT.md guardrails are excellent:
doctor → analyze → participatedecision order, explicitDEPOSIT_READYhandoff before any on-chain action, hard block on autonomously callingjingswap_deposit_stx - Phase guard in
analyzeOpportunity(line ~515) correctly returnsWAIT_FOR_DEPOSIT_PHASEbefore computing discount, avoiding a misleading spread signal when deposits are closed dexStxPerSbtc === 0guard catches uninitialized-pool edge case before attempting division- Parallel contract reads (
Promise.all) infetchCycleStateandfetchPrices— efficient use of Hiro's API - Output contract is clean: all commands emit typed JSON to stdout, consistent
errorfield on failures
[suggestion] Duplicate tuple-decoder logic (jingswap-cycle-agent.ts:361–396)
decodeCycleTotals and decodeMinDeposits share an identical loop structure — same buf[offset++] / name-parse / uint-read pattern, just different return shapes. If the contract ever adds a third field to either tuple, both decoders need the same fix in two places.
// Shared helper: decode a Clarity tuple of N uint fields from hex
function decodeTuple(hex: string, fieldCount: number): Record<string, number> {
if (!hex || !hex.startsWith("0x0c")) return {};
const buf = Buffer.from(hex.slice(2), "hex");
let offset = 5; // 0c + 4-byte field count
const result: Record<string, number> = {};
for (let i = 0; i < fieldCount; i++) {
const nameLen = buf[offset++];
const name = buf.subarray(offset, offset + nameLen).toString("ascii");
offset += nameLen;
offset++; // skip uint type byte (0x01)
result[name] = parseInt(buf.subarray(offset, offset + 16).toString("hex"), 16);
offset += 16;
}
return result;
}
Then both decoders become one-liners using this helper.
[suggestion] Duplicate spread calculation in status command (lines ~616–618)
The oracle-vs-DEX discount math is already encapsulated in analyzeOpportunity. The status command recomputes it inline. If the formula changes (e.g., weighting DLMM vs XYK differently), it needs updating in two places. Consider calling analyzeOpportunity(state, prices, 0) and reading discountPct from the result, or extracting a computeSpread(prices) helper.
[question] decodeUint precision for large micro-STX values (line ~352)
parseInt(hex.slice(4), 16) on a 32-char hex string interprets a Clarity uint128. JavaScript's Number loses precision above 2^53 (~9 × 10^15). For current JingSwap cycle sizes this is fine — even 1M STX = 10^12 micro-STX fits comfortably. But if cycle totals ever approach very large values, silent precision loss could produce incorrect discount calculations. Worth a // safe for values < 2^53 comment at minimum; for future-proofing, a BigInt decode path would be safer.
[nit] Double fallback in XYK price (lines ~463–464 and ~491)
fetchPrices already falls back XYK to DLMM when xykRaw === 0, then analyzeOpportunity has dlmmStxPerBtc || xykStxPerBtc. Since xykStxPerBtc is already set to dlmmStxPerBtc in the zero case, the || in analyzeOpportunity will never actually use XYK as a fallback for DLMM. Minor logic confusion — a comment clarifying the intended fallback path would help the next reader.
Code quality notes:
- 506 lines for 4 commands is well-scoped; no over-engineering here
- The Clarity hex-decode logic is necessarily low-level, but comments explain the byte layout clearly
analyzeOpportunityearly-returns are clean and easy to follow
Operational note: We use the JingSwap jingswap skill in production for oracle-settled STX↔sBTC swaps. The Pyth feed IDs here (e62df6c8... BTC/USD, ec7a775f... STX/USD) match what we've seen in live data. The contract address (SPV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RCJDC22.sbtc-stx-jing-v2) is the correct v2 mainnet deployment.
Approving — the suggestions above are non-blocking quality improvements. The guardrails around execution are solid and the data-reading logic is correct.
|
Hey @teflonmusk — there's a CI blocker on this PR. The Typecheck, validate, and manifest freshness check is failing. You'll need to fix that before merge can happen. Check the logs: https://github.com/aibtcdev/skills/actions/runs/23965484536/job/69904430267 — payment is waiting on the merge, so let's get this resolved. 🐕🦺 |
tfireubs-ui
left a comment
There was a problem hiding this comment.
Reviewed: JingSwap cycle monitor skill. Read-only Hiro API calls, no wallet needed. Correctly gates deposits behind parent agent confirmation (DEPOSIT_READY output, never autonomous execution). Clean SKILL.md/AGENT.md format. LGTM.
Three skills were admin-merged on 2026-04-08 with the CI 'Typecheck, validate, and manifest freshness' job in FAILURE state. The Zod validation rules were tightened in #135 (merged 2026-03-13), 3+ weeks before these PRs landed. This commit fixes the failures so subsequent BFF comp merges land on a clean baseline. Fixes (frontmatter only, no code changes): hermetica-yield-rotator/SKILL.md (introduced by #273): - user-invocable: "true" → "false" (rule requires "false") - tags: trim to controlled vocab → "defi, write, mainnet-only, l2" jingswap-cycle-agent/SKILL.md (introduced by #294): - requires: MCP tool name → "wallet, jingswap" (valid skill dirs) - tags: trim to controlled vocab → "defi, write, mainnet-only, l2" sbtc-auto-funnel/SKILL.md (introduced by #278): - tags: trim to controlled vocab → "defi, write, mainnet-only, requires-funds, l2" skills.json regenerated via bun run manifest to reflect all changes. Also adds .quests/ to .gitignore (pre-staged harness addition). Refs: FINDINGS.md in .planning/2026-04-15-bff-comp-review-4/ Rule tightening: #135 Note to repo owner: branch protection on main should require the CI job so future comp batches cannot admin-merge past red CI. Co-Authored-By: Claude <noreply@anthropic.com>
Three skills admin-merged on 2026-04-08 with CI in FAILURE state. Zod validation rules were tightened in #135 (2026-03-13) before those PRs landed. Fixes frontmatter-only; no code changes. - hermetica-yield-rotator: user-invocable false; trim tags (#273) - jingswap-cycle-agent: valid requires + trim tags (#294) - sbtc-auto-funnel: trim tags (#278) Regenerates skills.json. All 152 SKILL.md files pass validate.
|
🏆 Congratulations @teflonmusk — Day 9 winner of the AIBTC x Bitflow Skills Competition! jingswap-cycle-agent is the JingSwap STX↔sBTC cycle monitor — real market awareness, actionable signal, clean execution loop. STX↔sBTC cycling is an underserved primitive and you built it right. Prize: $100 in BTC Your skill has been pushed to the official AIBTC skills registry: Well earned. 🌊 |
jingswap-cycle-agent
Author: @teflonmusk (Dual Cougar)
Competition PR: BitflowFinance/bff-skills#78
PR Title: Add jingswap-cycle-agent: JingSwap STX↔sBTC cycle monitor and participation agent
This skill was submitted to the AIBTC x Bitflow Skills Pay the Bills competition, reviewed by judging agents and the human panel, and approved as a Day 9 winner.
Frontmatter has been converted to the aibtcdev/skills
metadata:convention. Command paths updated to match this repo root-level skill layout.Files
jingswap-cycle-agent/SKILL.md— Skill definition with AIBTC-format frontmatterjingswap-cycle-agent/AGENT.md— Agent behavior rules and guardrailsjingswap-cycle-agent/jingswap-cycle-agent.ts— TypeScript implementationAttribution
Original author: @teflonmusk. The
metadata.authorfield in SKILL.md preserves their attribution permanently.Automated by BFF Skills Bot on merge of PR #78.