hodlmm-arb-executor
HODLMM Arb Executor
What it does
Detects price spreads between Bitflow XYK pool and HODLMM (DLMM) for sBTC/STX, then executes LP-based arb via MCP command objects. Entry: swap STX→sBTC on XYK (buy cheap), deposit sBTC to DLMM bins as LP (capture premium). Exit: withdraw LP from DLMM, swap sBTC→STX. Exit triggers: spread reversal or 2-hour max hold.
All execution is write-capable. --confirm is required for live MCP command emission. simulate shows the full decision pipeline without touching chain or state.
Why agents need it
Agents running sBTC/STX strategies need a way to act on spread signals, not just observe them. This skill closes the loop from price detection to LP position management — entry when spread is profitable, exit on reversal, hard timeout to avoid stale positions.
On-chain proof
Live execute --confirm --max-sats 10000 run on 2026-04-07T16:32Z demonstrated full pipeline against mainnet:
- Pyth: BTC=$68,347 STX=$0.2149 | age 1s ✅
- Hiro XYK: 317,086 STX/BTC | $1.31M TVL ✅
- Bitflow HODLMM (
dlmm_6): 311,100 STX/BTC | active bin 308 ✅ - Spread: 1.93% gross / 1.38% net —
profitable: true✅ - STX amount: 32.3 STX for 10,000 sats at live oracle price ✅
- entryBinId: 309 = activeBin 308 + 1 ✅
- State: openPosition written, cooldown stamped ✅
On-chain swap tx (STX→sBTC via Bitflow XYK, wallet SP1KNKVXNNS9B6TBBT8YTM2VTYKVZYWS65TTRD430):
a34388332765330ff0299e598757078c7512c0db8dfd7dd96737b6ba9753e424 — SUCCESS (ok u10064) — 10,064 sats sBTC received.
Explorer: https://explorer.hiro.so/txid/a34388332765330ff0299e598757078c7512c0db8dfd7dd96737b6ba9753e424?chain=mainnet
Post-conditions: STX eq 32,300,024 micro-STX (debit from wallet) + sbtc-token gte 9,850 sats (sent from pool). 32.3 STX debited, 10,064 sats received. The bitflow_hodlmm_add_liquidity LP step can execute once sBTC confirms.
HODLMM integration
Uses bitflow_hodlmm_add_liquidity for entry and bitflow_hodlmm_withdraw_liquidity for exit. Targets dlmm_6 (SM1FKXGNZJWSTWDWXQZJNF7B5TV5ZB235JTCXYXKD.dlmm-pool-stx-sbtc-v-1-bps-15, the STX/sBTC DLMM pool). Bonus-eligible for HODLMM integration prize.
Safety notes
- Hard spend cap:
MAX_AUTONOMOUS_SATS = 100_000(~$85 at $85k BTC) hardcoded in source constants — not just documentation. --confirmrequired: All write paths require--confirm. Without it:CONFIRM_REQUIREDstatus, no state changes.- Doctor-first preflight:
executefetches all three data sources before proceeding. Aborts withPREFLIGHT_FAILEDif any source is unreachable. - No DLMM = no execute: If HODLMM data is unavailable, executor refuses to guess spreads. Returns
PREFLIGHT_FAILED. - Cooldown guard:
lastExecutionAtis only stamped whencmds.length > 0. No-op runs (nothing to execute) never consume the cooldown window. - Post-conditions: All MCP commands carry
postConditionsarrays (FT debit eq, FT credit gte with slippage tolerance). - 2-hour max hold: LP positions auto-exit after 2 hours to prevent stale exposure.
- Oracle confidence buffer:
profitableflag requires net spread >(oracle.confidence.stx / oracle.stxUsd) * 100— not just net spread > 0. - No credential passthrough: Skill does not accept
--wallet-password. Unlock wallet before calling.
Commands
doctor
Preflight check: all data sources + cooldown + open position. Run before execute.
bun run hodlmm-arb-executor/hodlmm-arb-executor.ts doctor
simulate
Dry-run. Shows exact commands, amounts, decision logic. No --confirm needed. No state changes.
bun run hodlmm-arb-executor/hodlmm-arb-executor.ts simulate [--max-sats 100000]
execute
Full pipeline. Requires --confirm to emit live MCP commands.
bun run hodlmm-arb-executor/hodlmm-arb-executor.ts execute [--confirm] [--max-sats 100000]
watch
Continuous monitoring. Read-only. Alerts when spread exceeds threshold.
bun run hodlmm-arb-executor/hodlmm-arb-executor.ts watch [--interval 60] [--min-spread 0.3] [--max-scans 60]
Output contract
All outputs are JSON to stdout.
doctor:
{
"network": "mainnet",
"status": "ok | error",
"checks": [
{ "name": "pyth_hermes", "status": "ok | error", "detail": "BTC=$85000 STX=$0.21 | age 3s | conf STX=$0.000210" },
{ "name": "hiro_xyk_pool", "status": "ok | error", "detail": "296000 STX/BTC | $1.3M TVL" },
{ "name": "bitflow_hodlmm", "status": "ok | error", "detail": "298000 STX/BTC | active bin 500 | 42 bins" },
{ "name": "cooldown", "status": "ok | warn", "detail": "ready | COOLING DOWN — 8m remaining" },
{ "name": "open_position", "status": "ok | warn", "detail": "No open LP position | Open LP: 100000 sats | held 14m | timeout in 106m" }
],
"note": "All systems go. | PREFLIGHT_FAILED — fix errors before running execute.",
"maxAutonomousSats": 100000,
"timestamp": "2026-03-30T12:00:00.000Z"
}
simulate:
{
"network": "mainnet",
"mode": "simulate",
"pair": "sBTC/STX",
"oracle": { "btcUsd": 85000, "stxUsd": 0.2101, "stxPerBtc": 404569 },
"xyk": { "stxPerBtc": 400123 },
"dlmm": { "stxPerBtc": 406800, "activeBinId": 500, "source": "bitflow-api" },
"spread": {
"grossSpreadPct": 1.6636,
"estFeePct": 0.55,
"netSpreadPct": 1.1136,
"confidenceBuffer": 0.0823,
"profitable": true,
"xykStxPerBtc": 400123,
"dlmmStxPerBtc": 406800
},
"openPosition": null,
"wouldExecute": true,
"skipReason": null,
"entryCommands": [
{
"tool": "bitflow_swap",
"args": { "token_x": "token-stx", "token_y": "token-sbtc", "amount_in": "410.14", "slippage_tolerance": "0.015" },
"description": "Swap 410.14 STX for ~0.001 sBTC on Bitflow XYK (entry: buy cheap sBTC)",
"postConditions": ["FT debit STX eq 410140000 micro-STX", "FT credit sBTC gte 98500 sats (1.5% slippage)"]
},
{
"tool": "bitflow_hodlmm_add_liquidity",
"args": { "pool_id": "dlmm_6", "bins": "[{\"activeBinOffset\":1,\"xAmount\":\"100000\",\"yAmount\":\"0\"}]", "active_bin_tolerance": "{\"expectedBinId\":500,\"maxDeviation\":\"2\"}", "slippage_tolerance": "1.5" },
"description": "Add 0.001 sBTC to DLMM pool dlmm_6 bin +1 (LP entry at premium)",
"postConditions": ["FT debit sBTC eq 100000 sats", "LP tokens credited for pool dlmm_6"]
}
],
"maxSats": 100000,
"cooldownRemainingMs": 0,
"timestamp": "2026-03-30T12:00:00.000Z"
}
execute — CONFIRM_REQUIRED:
{
"status": "CONFIRM_REQUIRED",
"message": "Add --confirm to authorize MCP command emission.",
"network": "mainnet",
"note": "Max spend: 100000 sats (hard cap: 100000 sats)",
"timestamp": "2026-03-30T12:00:00.000Z"
}
execute — ENTRY_COMMANDS_EMITTED:
{
"status": "ENTRY_COMMANDS_EMITTED",
"network": "mainnet",
"spread": { "grossSpreadPct": 1.6636, "netSpreadPct": 1.1136, "profitable": true },
"satsCapped": 100000,
"maxAutonomousSats": 100000,
"commandCount": 2,
"commands": [ "...same as simulate entryCommands..." ],
"openPosition": { "entryTimestamp": "...", "entrySpreadPct": 1.6636, "entryBinId": 500, "satsSent": 100000, "estimatedEntryUsd": 85.0 },
"timestamp": "2026-03-30T12:00:00.000Z"
}
execute — SKIPPED:
{
"status": "SKIPPED",
"reason": "SPREAD_NOT_PROFITABLE | SPREAD_TOO_SMALL | COOLDOWN_ACTIVE | DLMM_UNAVAILABLE",
"spread": { "...": "..." },
"message": "descriptive message",
"timestamp": "2026-03-30T12:00:00.000Z"
}
execute — PREFLIGHT_FAILED:
{
"status": "PREFLIGHT_FAILED",
"error": "API error 503 at https://api.hiro.so/...",
"network": "mainnet",
"timestamp": "2026-03-30T12:00:00.000Z"
}
watch — compact poll:
{ "scan": 1, "alert": false, "xykStxPerBtc": 400123, "dlmmStxPerBtc": 406800, "grossSpreadPct": 1.66, "openPosition": "no", "timestamp": "..." }
watch — alert:
{ "scan": 3, "alert": true, "network": "mainnet", "pair": "sBTC/STX", "spread": { "..." }, "openPosition": null, "timestamp": "..." }
Error:
{ "error": "descriptive message" }
Known constraints
- DLMM data required for execute — degrades to read-only if Bitflow API is unavailable.
bitflow_swapauto-routes — cannot force a specific pool. SDK determines the route.- Entry direction is always "buy sBTC on XYK, LP on DLMM" — only when XYK is cheaper than DLMM.
- HODLMM bin offsets are recalculated on exit to account for active bin movement since entry.
- Fee estimates are static (XYK 30bps, DLMM 25bps). Actual HODLMM fees vary by bin distance.
- State is stored locally in
~/.hodlmm-arb-executor-state.json.
Origin
Winner of AIBTC x Bitflow Skills Pay the Bills competition. Original author: @ronkenx9 Competition PR: https://github.com/BitflowFinance/bff-skills/pull/379
More from aibtcdev/skills
arxiv-research
Fetch and compile arXiv papers on LLMs, autonomous agents, and AI infrastructure into scored, grouped research digests. Stores digests at ~/.aibtc/arxiv-research/digests/. No API key required.
178aibtc-news
aibtc.news decentralized intelligence platform — list and claim editorial beats, file authenticated signals (news items) with BIP-322 signatures, browse signals, check weighted leaderboard, review signals as publisher, and trigger daily brief compilation.
166aibtc-news-correspondent
Correspondent for aibtc.news: claim a beat, research daily using live on-chain and market data, file quality signals, earn $25 sBTC per signal included in the daily brief
157btc
Bitcoin L1 operations — check balances, estimate fees, list UTXOs, transfer BTC, and classify UTXOs as cardinal (safe to spend), ordinal (inscriptions), or rune (rune tokens). Data sourced from mempool.space and the Unisat API.
150aibtc-news-fact-checker
Side role: find and correct bad signals, earn leaderboard points per Publisher-approved correction (max 3/day)
149defi
DeFi operations on Stacks — ALEX DEX token swaps and liquidity pool queries, plus Zest Protocol lending (supply, withdraw, borrow, repay, claim rewards). All operations are mainnet-only. Write operations require an unlocked wallet.
148