Repository navigation
feat(stacking): move the stacking skill to pox-5 - #430
Conversation
pox-5 is the active PoX contract on mainnet (cycle 141+) and removed every pox-4 function the skill called. Port the pox-5 staking implementation from aibtcdev/aibtc-mcp-server#682: - StackingService rebuilt on pox-5: stake / stake-update / unstake with a signer manager, signer-set walk, claim-style detection, and sBTC reward pull + staker claim. Deny-mode post-conditions (staking lock amount, performs-PoX, sBTC only out of pox-5 / the manager). Pre-checks refuse before signing: prepare phase, already/not staking, unregistered signer, balance, 1-96 cycles. - Added over the MCP version: every write confirms pox-5 is still the network's active PoX contract, and a dependency seam replaces module mocks in tests. - CLI: get-pox-info, get-stacking-status, list-signers, stack-stx, extend-stacking, unstake-stx, get-rewards, claim-rewards; strict argument parsing; optional BTC payout calldata. - pillar-direct: Fast Pool stack and revoke refuse while pox-4 is not active (the Pillar wallet contract hardcodes pox-4). - btcAddressToPoxAddr in src/lib/utils/bitcoin.ts; POX_5 replaces POX_4. - @stacks/* bumped to ^7.6.0 for the staking and pox post-condition types. Closes #429. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…pin claim nonces Review follow-ups for the pox-5 port, verified against mainnet pox-5 and the live signer-manager contracts: - get-rewards / claim-rewards: pox-5's get-earned-staker-rewards reads the signer's rewards-per-token, which only advances when the manager pulls, so it reported 0 and claim-rewards refused before ever sending the pull. Project the claimable amount with pox-5's compute-earned-rewards over the cycle's global rewards-per-token. - extend-stacking: stake-update forwards calldata to the manager's validate-stake!, and Xverse/Fast Pool delete the stored BTC payout address when it is none. Require --btc-reward-address, --signer-calldata-hex or an explicit --sbtc-payout. - claim-rewards: pin consecutive nonces for the pull + claim pair. - Take the sBTC contract for reward post-conditions from /v2/pox pox_5_sbtc_contract (differs from the default sBTC on testnet). - Refuse writes within 3 burn blocks of the prepare phase. - Error messages name CLI subcommands, not MCP tool names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8a9036c to
01665a6
Compare
|
Review: rebased onto main (skills.json regenerated). Verified every pox-5 call against the live mainnet contract, its interface, 6 signer-manager contracts and ~450 real stake/stake-update/unstake txs: function names, arg order, calldata encoding (byte-identical to a real Xverse stake), pox-addr versions, post-conditions (Deny everywhere), cycle math and the fail-closed pox-5 guard all check out. Live mainnet reads match Hiro (status for a 12,000 STX staker: lock + unlock height 1172150 exact). Fixed in 01665a6:
+4 tests (22/22 stacking, 196 in src/lib). Known, not fixed: stake during an sBTC-bond rollover would abort on the uncovered refund (costs the fee, no loss); balance checks don't reserve the tx fee. No live broadcast was done — a small testnet stake → unstake is still worth running. |
Closes #429. Skills-side counterpart of aibtcdev/aibtc-mcp-server#682 (part of aibtc-mcp-server#677).
Why
pox-5 has been the active PoX contract on mainnet since cycle 141 and removed every function the stacking skill called. #424 made writes refuse; this adds real pox-5 staking.
What
Ported from aibtc-mcp-server#682, which I checked against mainnet before porting: its
stake,stake-updateandunstakearguments and post-conditions match real successful transactions, and its reward-claim post-conditions match the Xverse signer manager's payout code.get-pox-infoget-pox-info+ burn height: cycle, next cycle start, prepare phaseget-stacking-statusget-staker-info,get-bond-membership, locked/unlocked balancelist-signers(new)stack-stxstake(signer-manager, amount, num-cycles, start-burn-ht, signer-calldata)extend-stackingstake-update: extend, increase, switch signer, change payout calldataunstake-stx(new)unstakeget-rewards(new)claim-rewards(new)claim-staker-rewardsstack-stx/extend-stackingflags change: signer manager instead of a PoX BTC address and burn height. Optional--btc-reward-address(+--max-withdrawal-fee-sats) encodes{pox-addr, max-fee}calldata;--signer-calldata-hexpasses raw calldata.Differences from the MCP version
/v2/poxstill reports pox-5, and refuses before signing otherwise (fail closed if unreadable), keeping fix(stacking): refuse writes when pox-4 is not the active PoX contract; read pox-5 staking status #424's protection for a future PoX bump.StackingServicetakes an optional{ hiro, callContract }for tests, instead of module mocks, which leak across files underbun test.Also
pillar-direct:direct-stack-stx --pool fast-poolanddirect-revoke-fast-poolrefuse while pox-4 is not active (the Pillar wallet contract hardcodes pox-4; the real fix is on Pillar's side). The Stacking DAO path is unchanged.@stacks/*→ ^7.6.0 (staking / pox post-condition types). The lockfile change is limited to those packages.Verification
get-pox-info(cycle 143, prepare phase from 968350);list-signers→ 26 signers for cycle 144 (same as the MCP PR);get-stacking-statusfor a real Xverse staker → 500 STX, unlock burn height 1170050, matching Hiro'sburnchain_unlock_height;get-rewards→ claim stylestaker-arg.src/lib/services/stacking.service.test.ts: the 16 MCP tests ported, plus 2 for the active-contract guard (verified to fail with the guard removed).bun run typecheck,bun run validate;stacking/stacking.tsandpillar/pillar-direct.tstype-checked separately (the repo'stypecheckonly coverssrc/).bun test(Bun 1.4.2): 180 pass / 38 fail vsmain162 / 38. The 38 failures are the existing cross-file mock leak; x402 files pass alone (72/72) on 7.6.0.🤖 Generated with Claude Code