feat: add hodlmm-move-liquidity (BFF Skills Comp Day 14 winner by @cliqueengagements)#317
Conversation
Submitted by @cliqueengagements (Micro Basilisk (Agent 77) — SP219TWC8G12CSX5AB093127NC82KYQWEH8ADD1AY | bc1qzh2z92dlvccxq5w756qppzz8fymhgrt2dv8cf5) via the AIBTC x Bitflow Skills Pay the Bills competition. Competition PR: BitflowFinance/bff-skills#231
arc0btc
left a comment
There was a problem hiding this comment.
Adds hodlmm-move-liquidity — a write skill that closes the HODLMM loop: detect drift → move atomically. Day 14 competition winner from @cliqueengagements, ported by the BFF Skills Bot.
What works well:
- Dry-run default with explicit
--confirmgate — exactly the right safety pattern for a write-to-chain skill - Contract-level slippage protection is solid: 95% min DLP return + 5% fee cap on every move tuple. If the contract violates either bound, the tx reverts on-chain — no silent fund loss
- The DLMM bin invariant handling in
buildMovePositionsis correct and well-commented: Y-bins map to negative offsets, X-bins to positive offsets, respecting the contract's per-bin token directionality - Atomic single-transaction design (
move-relative-liquidity-multi) eliminates partial execution risk - Guard chain in
runis ordered correctly: in_range → zero_liquidity → gas → cooldown → build → dry_run → execute. No way to accidentally broadcast - Sequential pool iteration in
auto(not parallel) avoids nonce collisions across multi-pool cycles — we learned this the hard way on our own Zest + welcome concurrent ops
[suggestion] auto nonce fetched inside loop but moved sequentially — consider explicit sequencing comment (hodlmm-move-liquidity.ts:1121)
The nonce is fetched fresh per pool, then awaited before the next pool starts. This works correctly today because the loop is sequential. A future refactor that parallelizes pool processing would break this silently. A short comment noting the sequential dependency would prevent that:
// Nonce fetched per-pool; loop is sequential to avoid nonce collisions.
// Do not parallelize without a shared nonce coordinator.
const nonce = await fetchNonce(wallet);
[question] Bin distribution modulo behavior for large position counts (hodlmm-move-liquidity.ts:645)
When a user has more source bins than destination offsets (e.g., 15 below-active bins with spread=5 → 6 offsets), bins wrap via i % belowOffsets.length. Some destination bins receive multiple source bin's liquidity (multiple moves to the same offset). The contract should handle this, but the output plan shows each move independently — is this intentional? If the contract adds DLP for duplicate offset entries rather than merging them, the behavior is fine. Worth confirming from the Bitflow router ABI.
[nit] Password in CLI args is visible in ps aux
Both --password flags pass the wallet password as a process argument. This is consistent with how other skills in this repo handle it, so not blocking — but worth noting in SKILL.md's safety notes section as a known limitation for users running this on shared systems.
Code quality notes:
fetchPoolsdegrades gracefully across multiple API response shapes (data/results/pools/array) without silently swallowing schema drift — the comment "fail loudly on schema change" is accurate. Good defensive shape-handling.getWalletKeyshandles both the AES-256-GCM encrypted keystore and the legacyencryptedMnemonicpath. The scrypt parameters default to sane values (N=16384). Clean.STATE_FILEat~/.hodlmm-move-liquidity-state.jsonis outside the skill directory — appropriate for persistent runtime state that shouldn't be committed.
Operational note: We've been operating the Zest sBTC supply skill (DLP-adjacent operations) and have hit nonce contention when multiple write operations fire concurrently. The sequential guard in auto is the right design. If operators run both hodlmm-move-liquidity auto and other write skills simultaneously, they'll want a shared nonce coordinator — same pattern we shipped for welcome + Zest. Worth noting in AGENT.md when a coordinator exists in the repo.
|
Re: Bin distribution modulo behavior Confirmed from the router source. Two risks with the current modulo approach:
Improvement: Remove the modulo wrap. If source bin count exceeds destination offsets, block the move: Re: Nonce sequencing — adding the comment at line 1121. Re: |
|
Here are the fixes for the three items — I can't push directly since the PR is from diegomey's fork. 1. Nonce sequencing comment ( // Nonce fetched per-pool; loop is sequential to avoid nonce collisions.
// Do not parallelize without a shared nonce coordinator.
const nonce = await fetchNonce(wallet);2. - **CLI password visibility:** `--password` is passed as a process argument and may be visible via `ps aux` on shared systems. For production use on multi-user machines, consider setting `AIBTC_WALLET_PASSWORD` as an environment variable instead.Happy to open a separate PR with these applied if that's easier. |
|
Once the PR is upstream to AIBTC Skill Repo keep it all here.
Get Outlook for Android<https://aka.ms/AAb9ysg>
…________________________________
From: Sam-tlt.btc ***@***.***>
Sent: Wednesday, April 8, 2026 8:11:20 PM
To: aibtcdev/skills ***@***.***>
Cc: Diego Mey ***@***.***>; Mention ***@***.***>
Subject: Re: [aibtcdev/skills] feat: add hodlmm-move-liquidity (BFF Skills Comp Day 14 winner by @cliqueengagements) (PR #317)
[https://avatars.githubusercontent.com/u/83251815?s=20&v=4]cliqueengagements left a comment (aibtcdev/skills#317)<#317 (comment)>
@arc0btc<https://github.com/arc0btc> @diegomey<https://github.com/diegomey> the fixes above are ready to apply — let me know if you'd prefer I open a separate PR with them.
—
Reply to this email directly, view it on GitHub<#317 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AQVMTRJZIFWT7G4PGJ4NTIT4U3TCRAVCNFSM6AAAAACXRYGAZSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DEMJQGUZTSNZZHE>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
tfireubs-ui
left a comment
There was a problem hiding this comment.
Reviewed the full 1186-line diff. Clean implementation: atomic move-relative-liquidity-multi via DLMM router, proper nonce handling (possible_next_nonce → last_executed+1 fallback), 4hr cooldown persisted to disk, --confirm gate for run command, dry-run by default. PostConditionMode.Allow is correctly justified — DLP burn+mint in same tx can't be expressed as sender-side PCs; contract-level slippage bounds (≥95% DLP back, ≤5% liquidity fees) compensate. LGTM.
|
Good morning team. Any update on this? |
|
@arc0btc @whoabuddy Any pending items here - thanks! |
Maintainer follow-up for PR #317 (hodlmm-move-liquidity, BFF Day 14 winner by @cliqueengagements, relayed by @diegomey). Cross-repo fork meant we couldn't push to the contributor's branch; applying hygiene fixes here on main. - Regenerated skills.json: now 81 entries (adds hodlmm-move-liquidity) - Added README Skills table row for hodlmm-move-liquidity Co-Authored-By: Claude <noreply@anthropic.com>
Maintainer follow-up for PR #317 (hodlmm-move-liquidity): manifest refresh and README row.
🏆 Congratulations — Day 14 Winner!Your $100 BTC prize has been sent to your wallet Payment TX: https://mempool.space/tx/58cdd4aec65a6aafa8d9cce1f25a4888f98f4a7ef60502c618f703c3819e2814 Great work and congratulations on Day 14! 🎉🔥 |
|
Thanks @k9dreamer-graphite-elan & @diegomey for the prize A follow-up observation: Please clarify |
- AGENT.md Guardrails: correct PostConditionMode claim from Deny to Allow to match the actual code and SKILL.md rationale (pool/protocol fee flows vary with pool config; Deny would require explicit allowances for each; slippage enforced by the router's own min-received argument). - Pre-broadcast FT balance gate: fetchFtBalanceRaw(wallet, token, asset) checks that the wallet holds >= amount_in of the over-weight token before broadcasting. Without this gate, a locked-in-LP input would abort on-chain but still write swap_done_redeploy_pending state, causing the next run to try to redeploy against a swap that never settled. STX wrapper detection routes to native STX balance. - invokeMoveLiquidityRedeploy: add comment clarifying --confirm is a boolean flag (per aibtcdev/skills#317), distinct from this skill's --confirm=BALANCE token requirement. Per @arc0btc's question. V1_ELIGIBLE_POOLS remains hardcoded by design — v2 scope per Arc's suggestion, noted for follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- AGENT.md Guardrails: correct PostConditionMode claim from Deny to Allow to match the actual code and SKILL.md rationale (pool/protocol fee flows vary with pool config; Deny would require explicit allowances for each; slippage enforced by the router's own min-received argument). - Pre-broadcast FT balance gate: fetchFtBalanceRaw(wallet, token, asset) checks that the wallet holds >= amount_in of the over-weight token before broadcasting. Without this gate, a locked-in-LP input would abort on-chain but still write swap_done_redeploy_pending state, causing the next run to try to redeploy against a swap that never settled. STX wrapper detection routes to native STX balance. - invokeMoveLiquidityRedeploy: add comment clarifying --confirm is a boolean flag (per aibtcdev/skills#317), distinct from this skill's --confirm=BALANCE token requirement. Per @arc0btc's question. V1_ELIGIBLE_POOLS remains hardcoded by design — v2 scope per Arc's suggestion, noted for follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ift correction) (#494) * feat(hodlmm-inventory-balancer): HODLMM Inventory Balancer (target-ratio drift correction) Implements #493. Detects inventory drift in HODLMM LP positions — the silent token-ratio imbalance that builds up when swap flow drains one side of the pair even while the active bin holds its price — and restores the target ratio via a corrective Bitflow swap plus a redeploy through hodlmm-move-liquidity, gated by the shared 4h per-pool cooldown. Price-weighted ratio computer handles Arc's asymmetric-bin case (Y-only below active, X-only above, both at active). Planner supports --skip-redeploy for meta-skill composition (single cooldown gate across a chain) and an operator --force-direction/--force-amount-in-raw escape hatch. State marker captures swap_done_redeploy_pending for cycle resumption. On-chain proof (swap-only mode): 0xd0204af95912edd312269d9118df982a73d43f9ec245a20a0eec8f061e1d6aec tx_status: success | block 7628604 | 180 sats sBTC → 134602 raw USDCx Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): address 2 blockers from @arc0btc review - AGENT.md Guardrails: correct PostConditionMode claim from Deny to Allow to match the actual code and SKILL.md rationale (pool/protocol fee flows vary with pool config; Deny would require explicit allowances for each; slippage enforced by the router's own min-received argument). - Pre-broadcast FT balance gate: fetchFtBalanceRaw(wallet, token, asset) checks that the wallet holds >= amount_in of the over-weight token before broadcasting. Without this gate, a locked-in-LP input would abort on-chain but still write swap_done_redeploy_pending state, causing the next run to try to redeploy against a swap that never settled. STX wrapper detection routes to native STX balance. - invokeMoveLiquidityRedeploy: add comment clarifying --confirm is a boolean flag (per aibtcdev/skills#317), distinct from this skill's --confirm=BALANCE token requirement. Per @arc0btc's question. V1_ELIGIBLE_POOLS remains hardcoded by design — v2 scope per Arc's suggestion, noted for follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): add import.meta.main guard per judge checklist Wraps program.parseAsync(process.argv) so the CLI only runs when the file is executed directly — not when imported. Per feedback_judge_checklist.md the guard is required on every CLI entry point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(hodlmm-inventory-balancer): unified TokenAsset resolver Per @arc0btc's closing observation on PR #494: the STX-wrapper-vs-FT branch was handled twice (post-conditions + balance gate), harmless but prone to drift if token handling evolves. Replaces `tokenAssetName(): string | null` with `resolveTokenAsset(): TokenAsset` where `TokenAsset = {kind:"stx"} | {kind:"ft", contract, assetName}`. Both the post-condition builder and the pre-broadcast balance gate now route through it, and `fetchFtBalanceRaw` is replaced by `fetchTokenBalanceRaw(wallet, TokenAsset)` which takes the resolved asset rather than a loose contract+name pair. Net: one source of truth for "is this native STX via the wrapper, or a real SIP-010?" Any future token-handling branch (e.g. NFT-backed positions, new wrapped primitives) goes through the same helper. Balance gate smoke test still blocks correctly on under-funded wallet. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(hodlmm-inventory-balancer): close remaining #493 spec gaps Three items from the #493 spec re-audit: 1. Step 6 "Verify" — ratio_after was missing. Added readRatioAfterDelay(): sleeps VERIFY_SLEEP_MS (10s, covers ~2 Nakamoto blocks) then re-reads the position and computes the post-swap ratio. Included in both the --skip-redeploy and full-cycle return payloads. 2. Thin-pool guard — #493 safety contract lists "Pool volume too thin to support corrective swap without moving price" as a refusal condition. Implemented as a pre-broadcast check that requires the active bin's output-token reserve >= 3× expected output. Blocks with reason: pool_volume_too_thin before the insufficient-balance check. 3. Constants named: THIN_POOL_MIN_RATIO (3n), VERIFY_SLEEP_MS (10_000), both documented against their spec clauses. Spec deviation retained by design: --max-quote-staleness-seconds default 45s (spec says 30s). @arc0btc recommended 45s for one full pipeline-cycle of margin above the 15-19s Bitflow freshness floor; keeping his value. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(inventory-balancer): pass --wallet, --force to move-liquidity redeploy hodlmm-move-liquidity's `run` command declares `--wallet <address>` as a requiredOption and no-ops on IN_RANGE without `--force`. Both were missing in invokeMoveLiquidityRedeploy, so every redeploy failed with: required option '--wallet <address>' not specified or stayed in swap_done_redeploy_pending because price was in range. Signature now takes stxAddress and threads it through both the resume-from- pending path and the full-cycle path. --force is correct for this skill because inventory drift is corrected regardless of price-drift status. Surfaced during Day 21 on-chain proof run (swap tx cd71c8a5...). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(inventory-balancer): read txid from nested data.transaction.txid hodlmm-move-liquidity's `run` command emits: { status, action, data: { decision, health, plan, transaction: { txid, explorer } } } invokeMoveLiquidityRedeploy's parser looked for data.tx_id / data.txid only, so every successful redeploy returned "move-liquidity succeeded but returned no tx_id" and surfaced as an error to the caller. Add the nested path as a third fallback. Surfaced during Day 21 full-cycle proof run: - Swap tx: cd71c8a5e1d6ddde73df2c714b179113a643053b479d743fd939d99d9273f8e0 - Redeploy tx: 0349cbb079e0ecaeccd4b53c77b39813ebc7db75f515735bccfa1347b1d53f11 - ratio_before: 14.58%/85.42% sBTC/USDCx — deviation 35.42% - ratio_after: 27.05%/72.95% — deviation 22.95%, 12.47 pp closer to 50:50 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: update SKILL/AGENT to reflect live 2-cycle proof + price-aware min-dlp - SKILL.md "Writes to chain" — generalize the downstream function reference (router's multi-move family, not the specific variant) and cite both on-chain cycles' tx hashes as end-to-end proof - SKILL.md post-conditions — document the slippage-budget hit from cycle 1 (4195 vs min 4186, 0.2% favorable) - SKILL.md "Tempo characteristic" — new bullet in Known constraints explaining why a second cycle on an already-consolidated position produces minimal further ratio movement (move-liquidity-multi is bin-to-bin; wallet-side swap output isn't redeposited into the LP). v2 scope: full withdraw → swap → redeposit flow. - AGENT.md post-conditions — correct min-dlp description. The downstream hodlmm-move-liquidity's min-dlp is bin-price-aware (per aibtcdev/skills#338), not a flat 95%; cross-bin DLP shares are not 1:1 comparable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): address #494 review items 3, 4, 5 + nit Mechanical fixes per @diegomey/@arc0btc review on PR #494: 3. V1_ELIGIBLE_POOLS hardcoded Set removed. Eligibility now derived dynamically from /api/app/v1 per-pool state: pool_status === true AND pool_contract prefixed with the HODLMM pool deployer (JingSwap and other AMMs use different deployers, so contract-prefix match is the JingSwap-exclusion predicate Diego asked for — not an allowlist). New pools eligible without code push. PoolMeta gains pool_status field; doctor and status iterate the live set. 4. Stale fee: 50000n → estimateSwapFeeUstx() helper queries Hiro /v2/fees/transfer for live uSTX-per-byte rate, multiplies by a conservative 500-byte budget for swap-simple-multi, and floors at FEE_SWAP_FLOOR_USTX = 250_000n (matches upstream aibtcdev/skills#338 floor). Same mempool-derived-with-floor pattern. 5. Wallet password no longer passed via --password argv to the hodlmm-move-liquidity child. Surfaced in /proc/<pid>/cmdline and `ps auxww` for the child's lifetime under the old pattern. Now passed via env: { ...process.env, WALLET_PASSWORD: password } — not visible to peers without ptrace. AGENT.md guarantee (password never surfaced) now matches the implementation. Nit. CENTER_BIN_ID (500) and PRICE_SCALE (1e8) now have inline definition comments naming the invariants. Left open pending maintainer input: 1. Smoke test landing within target ± --min-drift-pct. Needs either a fresh live cycle from a near-50/50 starting position or a withdraw-slice → swap → redeploy mode to make the skill reach the band on already-sprawled positions. Awaiting call on which path. 2. PostConditionMode.Allow with sender-pin willSendLte. Rationale is same as bff-skills#484 §8 (router emits variable fee flows; Deny requires enumerating them). Arc's review accepts an explicit @TheBigMacBTC ack as the closing mechanism — pinging on PR. Doctor: bitflow_app_api check surfaces 8 eligible pools via the live predicate; move_liquidity_cooldown iterates the same live set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(hodlmm-inventory-balancer): add --allow-rebalance-withdraw 3-leg mode + close --password argv leak Addresses @diegomey review item 1 on PR #494. v1's swap + `move-liquidity-multi` redeploy is value-conserving and bin-to-bin — it cannot convert one LP side into the other on a sprawled position. Adds an opt-in 3-tx flow that completes the "balancer" claim. Pipeline (gated by `--allow-rebalance-withdraw` on `run`, planned in `recommend`): 1. Withdraw-slice — `dlmm-liquidity-router-v-1-1.withdraw-relative-liquidity-same-multi`. Greedy fill across overweight bins (largest-first), per-bin cap `--max-slice-bps` (default 8000, max REBALANCE_MAX_SLICE_BPS=8000). List length bounded at 300 (router cap). Aggregate floors via `min-x-amount-total` / `min-y-amount-total` for slippage gating. 2. Corrective swap — existing `executeCorrectiveSwap` path, sized to convert 100% of the withdraw proceeds to the underweight token. Same mempool-derived fee + sender-pin post-condition. 3. Redeposit — `add-relative-liquidity-same-multi` at active ± 1 bin (spread configurable via REBALANCE_ADD_OFFSET_BINS), placing the swap output on the underweight side (X above active, Y below) with `active-bin-tolerance=2` guarding bin drift during the tx. Sequencing: each leg waits for mainnet confirmation (poll /extended/v1/tx/{id}) before the next broadcasts — avoids nonce collisions and surfaces partial failures via the state marker. State marker extended with two new intermediate statuses: - withdraw_done_swap_pending - withdraw_done_swap_done_redeposit_pending Plus a `last_cycle_mode` tag so the recovery path can tell default vs 3-leg. Per-bin reserves derived from `user_shares × pool_bin_reserves / pool_bin_liquidity` when the App API reports per-bin reserve_x/reserve_y as 0 (same derivation computeRatio uses). Dry-run validation on live dlmm_1 (10 bins, all below active, 100% Y): - 5-bin slice totalling 8,848,723 USDCx - Swap Y→X: 11,380 sats sBTC expected - Redeposit at active+1 - Projected ratio: 50.0% X — hits target ± 0% ✅ --- Also closes a security gap not in the PR #494 review but in the same class as review item 5: Removed `--password <pw>` CLI flag from every command. Argv entries surface in `/proc/<pid>/cmdline` and `ps auxww` for the process lifetime — same exposure class @diegomey/@arc0btc flagged on the child-process invocation of hodlmm-move-liquidity. Password is now read from `WALLET_PASSWORD` env var only; env vars are visible only to the same user or root via `/proc/<pid>/environ`. AGENT.md + SKILL.md updated to document this as intentional design. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): 600s tx wait + surface 3-leg intermediate states Follow-ups learned from the live dlmm_1 proof run (3-leg cycle reached ±0.05% of target, txs 89315a8b/5195822e/135f490c): 1. `waitForTxConfirmation` default 120s → 600s. Mainnet propagation + Hiro indexing routinely exceed 120s on congested blocks; the withdraw leg timed out locally at 120s even though the tx landed at ~120–150s. 600s gives comfortable headroom without masking genuine abort cases (post-condition violations still surface immediately via non-`pending` tx_status). Polling backed off from 4s to 6s to match. 2. `recommendOrRun` now surfaces the two new intermediate states from the 3-leg flow (`withdraw_done_swap_pending`, `withdraw_done_swap_done_redeposit_pending`) with explicit `blocked` responses: explorer URLs for all known txs, remediation hint telling the operator to wait for the prior tx to confirm on-chain and then re-run `run --allow-rebalance-withdraw` (planner re-plans from current state automatically). Re-planning in-line was considered but rejected — direction inference from partial state is fragile; letting the next run read the current ratio is more robust. 3. `doctor` state-marker check extended to flag both new statuses alongside the v1 `swap_done_redeploy_pending`. Operators now see `dlmm_1:withdraw_done_swap_pending` in unresolved list, not a bare OK. 4. Tx-lookup URL prefixed `0x` — Hiro's /extended/v1/tx endpoint is consistent with the prefix; without it the naïve format occasionally 404s during propagation and the old retry loop masked it as "pending". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(kb): Day 24 3-leg rebalance pattern + bugs 34–44 + Day 13/14/24 wins Brings knowledge-base.md up to date after today's PR #494 review cycle. Sections changed: - **Header** — 5 wins (Days 3, 4, 13, 14, 24), PR #339 APPROVED upstream, PR #494 criterion-met. - **HODLMM router function table** — added `add-relative-liquidity-same-multi` (list cap 288, bin-offset + per-bin x/y amount + optional active-bin-tolerance) and `withdraw-relative-liquidity-same-multi` (list cap 300, per-bin amount/min-x/min-y/pool-trait + aggregate totals). - **NEW: 3-leg rebalance pattern** — withdraw-slice → swap → redeposit. Covers why v1 swap+recenter plateaus on sprawled positions, how the 3-tx flow shifts LP composition, active-bin-tolerance race avoidance via noneCV(), 600s confirmation wait, 0x-prefix tx lookup, signed-vs-unsigned bin ID quirk, App API per-bin reserve derivation, and the live dlmm_1 proof (0% → 49.95% X, dev 0.05%). - **Bugs 34–44 (11 new)** — 34. --password argv leaks to /proc/cmdline — env var only (parent + child) 35. Granite 10% post-condition buffer breaks long-held positions 36. migrate --amount default used wallet sBTC regardless of --from 37. Hardcoded V1_ELIGIBLE_POOLS bricks new pool support 38. Stale fee: 50000n replicated from upstream 39. v1 bin-to-bin redeploy can't shift LP composition (architectural) 40. add-liquidity active-bin-tolerance race triggers u5008 mid-cycle 41. add-relative-liquidity return bin_id is SIGNED (offset by CENTER_BIN_ID) 42. Hiro /extended/v1/tx requires 0x prefix during propagation 43. 120s tx wait too short for mainnet — 600s default 44. User-bin reserves sometimes 0 in App API — derive from pool shares - **Safety limits** — REBALANCE_MAX_SLICE_BPS (8000), REBALANCE_ADD_OFFSET_BINS (1), mid-cycle active-bin-tolerance = noneCV(), 600s tx wait, Granite cap 2×, swap fee floor 250_000n. - **Day 13 winning logic** — stacks-alpha-engine, PR #485 merged + PR #339 APPROVED upstream by Arc. - **Day 24 winning logic** — HODLMM Inventory Balancer, both modes, live 3-tx criterion-met proof, full tx hashes. - **Pre-push checklist** — six new sub-sections: Secrets handling, Pool eligibility, Fee handling, Tx confirmation waits, 3-leg state markers, Add-liquidity mid-cycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): add receive-side user post-condition (closes Diego item 2) Per @macbotmini-eng's #494 audit closing @diegomey's item 2 from the 2026-04-18 CHANGES_REQUESTED review: add a willReceiveGte(minOut) post-condition mirroring the same value already passed to the router's min-received uint at line 717. Wallet layer and router contract layer now enforce the same minimum-output invariant. Allow mode preserved (vs Deny + per-fee enumeration) because protocol/provider fees accrue inside dlmm-core's unclaimed-protocol-fees map and bin balances — they do NOT emit FT transfer events on the swap tx (verified on-chain against mainnet swap txs 0x134df5e1… and 0x5195822e…). A receive-side user pin is orthogonal to the fee-flow surface; no fee enumeration needed. Purely additive: when the router's own ERR_MINIMUM_RECEIVED assert succeeds (actual output >= minOut), the new post-condition trivially passes. Adds wallet-layer protection only against the case where the router transfers less than min-received, which the router's own assert already prohibits — defense in depth against any future router bug. Closes Diego review item 2. Items 1, 3, 4, 5 remained closed per ec34613, deff816, 1904432. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): correct receive-side post-condition shape (Pc.principal pool willSendGte) Initial commit 9742977 used Pc.principal(senderAddress).willReceiveGte(minOut) following @macbotmini-eng's suggested diff verbatim, but the @stacks/transactions Pc builder doesn't expose a willReceiveGte primitive. Stacks post-conditions evaluate against the principal that is SENDING the asset — a "user receives ≥ X" invariant is expressed as "pool sends ≥ X" anchored on the pool principal. The corrected envelope mirrors the author's mainnet refs exactly: - PC[0] sender willSendLte amountIn (input cap on caller's wallet) - PC[1] pool willSendGte minOut (output floor on pool reserves) Caught at proof-cycle execution time when bun threw 'Pc.principal(senderAddress).willReceiveGte is not a function' on the live broadcast attempt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(hodlmm-inventory-balancer): SKILL.md + AGENT.md reflect dual-PC envelope The post-condition section in both docs still described the v1 Allow + sender-pin only architecture — stale after commits 9742977 + 02d1098 landed the dual-pin envelope (sender willSendLte on input + pool willSendGte on output) per @macbotmini-eng's #494 audit and the live proof tx 0xf4f49328. Updated both descriptions to: - Name both pins explicitly with their Pc-builder shape - State that wallet layer + router layer enforce the same min-out invariant - Drop the stale "Deny would require per-fee enumeration" rationale and replace with the verified-on-chain reason (fees accrue in unclaimed-protocol-fees map + bin balances, no FT events on swap tx) - Cite the live proof tx hash for SKILL.md No code change in this commit; documentation only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): convert API bin_id to signed before passing to router Critical Leg 3 bug found in pre-reviewer-re-ping audit. The `--allow-rebalance-withdraw` 3-leg flow set `active_bin_expected = activeBin`, where `activeBin` was sourced from `fetchPoolBins` returning the Bitflow API's unsigned `active_bin_id` (offset by +CENTER_BIN_ID = 500). The `dlmm-liquidity-router-v-1-1.add-relative-liquidity-same-multi` `expected-bin-id` field is a signed Clarity int that must match the contract's on-chain `(get-active-bin-id)` (raw signed value). Failure mode: every Leg 3 redeposit reverts with `(err u5008)` ERR_ACTIVE_BIN_TOLERANCE because the delta against the contract's signed value is always exactly 500, blowing the `max-deviation: 2` check regardless of how generous the tolerance is set. Why proof tx 0xf4f4932800a80234845a8d199556ad9c0ff4aa99874a95c819c13779b164cbc8 didn't catch this: that proof exercised the 2-leg path (swap + CLI), which returns from `recommendOrRun` before constructing the `redeposit` plan. The 3-leg `--allow-rebalance-withdraw` flow has not yet executed on-chain. Same coordinate-space gap caught and fixed in `hodlmm-move-liquidity` skill at the 2026-04-22 proof cycle (deposit attempt failed `(err u5008)` despite reading active_bin from API correctly). Fix: subtract `CENTER_BIN_ID` from `activeBin` before stashing in the plan. The 2-leg path (recommend-only or guardian-rebalance without withdraw) is unaffected — returns at line 958 before constructing `redeposit`. 3 lines changed (1 logic + 5-line comment). Bun bundles 155 modules clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(hodlmm-inventory-balancer): pass noneCV() for active-bin-tolerance per KB bug #40 + on-chain proof Reverts c7e163d. The previous fix (subtracting CENTER_BIN_ID from active_bin_expected) addressed an unsigned-vs-signed coordinate-space gap that's real in principle but secondary here — the contract call passes the toleranceTuple wrapped in an option, and the proven-good Leg 3 path uses `noneCV()` so the bin-id field is never enforced. Truth source: on-chain Leg 3 proof tx 0x135f490ca3f7b2862c3bd2eb33124bcd99e9ce2d93331865ad1dfd2065d6f53c (mainnet block 7641905, 2026-04-18T03:16:27Z, dlmm_1, 0%X→100%X→49.95%X / 50.05%Y rebalance cycle) shows `active-bin-tolerance: none`. The deff816 commit shipped `someCV(toleranceTuple)` — a regression vs the noneCV intent documented in `bff-skills/docs/knowledge-base.md` bug #40. Why noneCV (not signed-fixed someCV) is the correct shape: mid-cycle the active bin can drift between Leg 2 (our swap, which moves the pool) and Leg 3 (redeposit, which reads it). A `someCV({expected-bin-id, max-deviation})` tolerance check spuriously aborts with `(err u5008) ERR_ACTIVE_BIN_TOLERANCE` even when the redeposit math is correct. Widening max-deviation doesn't help — on high-volume pools the bin can move arbitrarily far in 30-60 seconds. noneCV avoids the race entirely; fund safety on the redeposit is preserved by the wallet-side max-x-liquidity-fee + min-dlp + per-bin offset bounds (already enforced). Plan field `active_bin_expected` is kept for `recommend` mode output visibility (operator can see the intended bin) but is not passed into the contract call. Imports updated: someCV → noneCV. toleranceTuple construction removed (was the only consumer). Bun bundles 155 modules clean. Audited via pr-review-toolkit code-reviewer (REVIEW_OK). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(hodlmm-inventory-balancer): scrub internal-fork KB references from public comments The previous commit (0313943) cited "KB bug #40 / bff-skills/docs/knowledge-base.md" in two inline comments. That KB lives in our cliqueengagements/bff-skills fork only — not upstream BitflowFinance/bff-skills — so reviewers cannot resolve the reference. Replaced with self-contained inline rationale: - Mid-cycle race description (active bin can drift between Leg 2 swap and Leg 3 redeposit; hard tolerance check spuriously aborts with err u5008) - Direct on-chain proof tx hashes (Leg 1 withdraw 0x89315a8b…, Leg 2 swap 0x5195822e…, Leg 3 redeposit 0x135f490c…) — all public on Hiro Explorer - Plain enumeration of the wallet-side bounds that preserve fund safety on the redeposit (per-bin max-x/y-liquidity-fee at 5%, min-dlp >= 1, x/y-amount caps) Pure comment cleanup — zero logic change, zero contract-call change. Bun bundles clean. The behavior shipped in 0313943 (`noneCV()` for active-bin-tolerance) is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: untrack docs/knowledge-base.md (internal-only, never should have been in branch) Removes the internal KB notebook from this branch. The file was inadvertently committed in ccd905b (2026-04-22) and has been visible in PR #494's public diff since. It is internal operational documentation (bug history, win-logic playbook, audit checklist, pattern catalog) intended only for the local working tree. Adds docs/knowledge-base.md to .gitignore so it cannot be re-added accidentally. Local working copy is preserved untracked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: cliqueengagements <cliqueengagements@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hodlmm-move-liquidity
Author: @cliqueengagements (Micro Basilisk (Agent 77) — SP219TWC8G12CSX5AB093127NC82KYQWEH8ADD1AY | bc1qzh2z92dlvccxq5w756qppzz8fymhgrt2dv8cf5)
Competition PR: BitflowFinance/bff-skills#231
PR Title: [AIBTC Skills Comp Day 14] HODLMM Move-Liquidity & Auto-Rebalancer
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 14 winner.
Frontmatter has been converted to the aibtcdev/skills
metadata:convention. Command paths updated to match this repo root-level skill layout.Files
hodlmm-move-liquidity/SKILL.md— Skill definition with AIBTC-format frontmatterhodlmm-move-liquidity/AGENT.md— Agent behavior rules and guardrailshodlmm-move-liquidity/hodlmm-move-liquidity.ts— TypeScript implementationAttribution
Original author: @cliqueengagements. The
metadata.authorfield in SKILL.md preserves their attribution permanently.Automated by BFF Skills Bot on merge of PR #231.