Stacks sBTC on mainnet. pip install "agentpay-x402[stacks]" and the
one-liner quickstart(stacks_key="…", prefer_chain="stacks") pay tools in
sBTC against agentpay.tools — sign-don't-broadcast, hard USD cap, receipts
chain-verified on the public ledger. Three mainnet receipts settled before
release (30689b5e…, d1de1a79…, 59ce7014…); the daily flagship agent
runs on the same rail. Everything below is the M2 hardening that went in
between 0.4.0 (testnet) and this release.
Fixed
- Stacks confirmation never seen — the gateway polled Hiro at
/extended/v1/tx/<txid>without0x; Hiro answers that with a 302 the
client did not follow, so every settle ended "uncertain" even after the
tx confirmed. The poll asks for the0xform (found on the first mainnet
settle, txid30689b5e…). - Uncertain reply swallowed by Cloudflare — the gateway's uncertain
settle answered 502, which Cloudflare replaces with its own HTML page in
front ofagentpay.tools; the SDK saw no JSON. It is 503 now, and a
5xx without a body on redeem keeps the redeem context instead of failing. - Refund contract reply was a 502 — the same Cloudflare replacement as
above hid therefund_pendingbody from the SDK onagentpay.tools; it
is a 500 now (payment_statusunchanged). AGE-155. - A gateway's
rejectedalone no longer zeroes a Stacks leg — the SDK
checks Hiro first; unless the tx is unknown or aborted on-chain the spend
stays recorded and the call endsSettlementUncertain(redeemable).
AGE-152. The gateway also stops treatingdropped_*as definitive. - Stacks settle wall time is bounded —
STACKS_SETTLE_DEADLINE_S
(75 s) turns a slow broadcast+confirm into a structureduncertain
before the edge's 100 s cut can strip the body. AGE-150. LEDGER_FLAGSHIP_ADDRESSESrejected Stacks addresses (SP…/ST…), so a
Stacks payer's receipts could never reach/ledger.- Stacks signing with a raw 64-hex key — the presign sighash cleared the
origin condition with the compressed key-encoding byte regardless of the
key, so uncompressed keys produced signatures the node rejected
(SignatureValidation). The sighash now keeps the key's own encoding;
both encodings are fixture-tested byte-for-byte against stacks.js.
Added
pip install "agentpay-x402[stacks]"— the Stacks extra (the core
install already carries the signing dependency; the extra mirrors[base]).quickstart(stacks_key=…, prefer_chain="stacks")— a Stacks-only
wallet skips registration and needs no Stellar secret; the session exposes
stacks_public_key.- Flagship analyst on the Stacks rail —
FLAGSHIP_STACKS_KEYputs the
daily cron's gateway-paid calls on sBTC (FLAGSHIP_RAILpinsstacks,
base, or alternates by day); an uncertain settle is redeemed once the
transaction confirms instead of being dropped; the Bazaar keepalive and
external x402 sellers stay on Base./ledger.jsonnames the Stacks payer
underwallets.stacks. agentpay._stacks_tx.verify_origin_signature(signed_tx)— pure check that
a signed transaction's origin signature recovers to its signer; the
gateway runs it before consuming replay state or broadcasting.Session.redeem(exc)/AgentPayClient.redeem(exc)— finish a Stacks
call that ended inSettlementUncertain: wait for the transaction to
confirm, then re-present the identical signed payment; the gateway
delivers exactly once per txid.SettlementUncertain.redeem_ctxcarries
whatredeemneeds.- Stacks mainnet —
AgentWallet(network="mainnet", stacks_key=…)pays
sBTC onstacks:1againstagentpay.tools; seedocs/stacks-mainnet.md.
examples/stacks_m1_demo.pytakesSTACKS_NETWORK=mainnet. Session.redeem_txid(txid, tool, params)/
AgentPayClient.uncertain_from_txid— redeem an uncertain Stacks settle
from the txid alone when the signing process is gone: the signed bytes
come from Hiro and the memo is the challenge id._stacks_tx.memo_of.
The demo takesSTACKS_REDEEM_TXID=<txid>.tools/stacks_derive_key.py— deriveSTACKS_AGENT_KEYfrom a Leather
24-word Secret Key (m/44'/5757'/0'/0/<account>), hidden prompt, key
written only with--print-key; tested against@stacks/wallet-sdk.
Changed
- The STX fee a 402 suggests is clamped to
STACKS_MAX_FEE_MICROSTX
(0.05 STX; env can only lower it) before signing — a gateway cannot name
the payer's fee freely. - Review lows (AGE-153): the memo must equal the challenge id cut to 34
bytes (a prefix rule let a 1-byte memo bind any id); the client floor
rate is $20,000 on mainnet ($10,000 testnet, raise-only); the gateway
quotes Hiro's medium fee tier capped at 20,000 µSTX; a replay-store
outage before broadcast answersrejectedwith a re-sign hint (the SDK
verifies absence on Hiro first) instead of an unfulfillable "retry the
same proof"; the in-memory txid guard is bounded;import osmoved to
module scope.