Skip to content

Commit a183ac8

Browse files
werner-stacksgitbook-bot
authored andcommitted
GITBOOK: Add operate/protocol-bonds with the bond pool operator guide
1 parent c120e03 commit a183ac8

3 files changed

Lines changed: 133 additions & 0 deletions

File tree

docs/operate/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@
3333
* [Operate a Pool](staking-stx/operate-a-pool.md)
3434
* [Generate a Signer Signature](staking-stx/generate-signer-signature.md)
3535
* [Key and Address Rotation](staking-stx/key-and-address-rotation.md)
36+
* [Protocol Bonds](protocol-bonds/README.md)
37+
* [Bond Pool (BTC + STX) Operator Guide](protocol-bonds/bond-pool-operator-guide.md)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
description: >-
3+
Protocol bonds pair a Bitcoin commitment with locked STX. Guides for running
4+
and ending a bond position.
5+
---
6+
7+
# Protocol Bonds
8+
9+
A protocol bond pairs a Bitcoin commitment with an STX lock for a 12-cycle term. The Bitcoin side is either a timelocked UTXO you hold on Bitcoin L1, or sBTC held by the contract.
10+
11+
This section is being built out. One guide is available now:
12+
13+
* [Bond pool operator guide](bond-pool-operator-guide.md) — running a whitelisted community sBTC pool.
14+
15+
For the conceptual overview, see [Bitcoin Staking](https://docs.stacks.co/learn/bitcoin-staking).
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
description: >-
3+
Running a whitelisted community-tranche sBTC bond pool under PoX-5:
4+
registration, monitoring, and the operator's escape hatches.
5+
---
6+
7+
# Bond Pool (BTC + STX) Operator Guide
8+
9+
This guide covers running a whitelisted community sBTC pool for PoX-5 protocol bonds. It is a different job from operating an STX-only pool, which is covered in [Operate a Pool](../staking-stx/operate-a-pool.md).
10+
11+
## Scope: sBTC pools only
12+
13+
The community allocation is sBTC-only via a pool. Native-BTC bonds are individual-only. The L1 path requires a lockup script committing to a single staker principal, so there is no pool path for it.
14+
15+
Each staker holds at most one bond membership, and the consequence shapes everything else here: **the pool contract itself is the PoX-5 staker**, not the members behind it. PoX-5 sees one membership keyed on your contract principal. Every member-level record lives in your contract.
16+
17+
## What a whitelisted pool operator does
18+
19+
Manage the community allocation, expected to be roughly 10% of paired BTC capacity in the protocol bond tranche during the PoX-5 bootstrap. Enroll members, lock pooled sBTC and STX, receive pool-level rewards, and distribute them pro rata.
20+
21+
Reward routing is not something you set at registration. There is no `pox-addr` argument on `register-for-bond`; where rewards land is a signer-manager concern, passed as opaque `signer-calldata`.
22+
23+
## Registration flow
24+
25+
* Members deposit STX and sBTC into your contract. The member-facing deposit flow is entirely yours to define; it is not part of pox-5.
26+
* Your contract calls `register-for-bond` **once**, with the aggregated member totals.
27+
* Prerequisites: your contract must already be registered as a signer with a live signer key grant, and must hold an allowance on that bond, or you get `ERR_NOT_ALLOWLISTED u11`. Exceeding the allowance returns `ERR_TOO_MUCH_SATS u10`.
28+
* The STX you commit must clear the bond's minimum for the sats you are locking, or `ERR_INSUFFICIENT_STX u8`. That minimum is a **fraction** of the BTC value at the published ratio, not full coverage of it. On-chain the floor is `min-ustx-for-sats-amount(sats-amount, stx-value-ratio, min-ustx-ratio)`, and both `stx-value-ratio` and `min-ustx-ratio` are per-bond parameters the bond admin supplies at `setup-bond`. The white paper's 5% is an illustrative value, not a constant. Read the live bond parameters.
29+
* You must also hold the STX. `register-for-bond` checks locked plus unlocked balance together and returns `ERR_INSUFFICIENT_STX u8` if the total falls short.
30+
* Registration must land before the bond's start height, or `ERR_BOND_ALREADY_STARTED u43`, and is rejected during the prepare phase with `ERR_STAKE_IN_PREPARE_PHASE u47`.
31+
32+
The pool is then bonded for the full 12-cycle term as a single membership.
33+
34+
### If members commit less than your allowance
35+
36+
The allowance is a ceiling, not a target. `register-for-bond` asserts only that `sats-total <= allowance`, failing with `ERR_TOO_MUCH_SATS u10` when the aggregate is too large; there is no minimum-commitment gate anywhere in the function. An under-subscribed pool therefore registers for the amount it actually raised, and that smaller amount is what gets staked.
37+
38+
## Persist the unlock bytes
39+
40+
The `staker-unlock-bytes` tail chosen at registration is **not stored on-chain**. Your contract cannot recover it later, and neither can pox-5. Persist it yourself for the pool's own lockup. Without it the P2WSH lock address cannot be rederived and the locked BTC cannot be reclaimed.
41+
42+
## Monitoring
43+
44+
Read-only calls compose an operator dashboard, all keyed on your contract principal as the signer, a reward cycle, and `(some bond-index)`:
45+
46+
| Call | Returns |
47+
| ------------------------------------------------ | ---------------------------------------------------------- |
48+
| `get-signer-unclaimed-rewards-for-cycle` | Settled but unclaimed sBTC |
49+
| `get-signer-rewards-per-token-settled-for-cycle` | The rewards-per-token snapshot at last settlement |
50+
| `get-earned` | Total claimable now, including accrual since that snapshot |
51+
52+
`get-earned` is the one to display. It composes the other two with your current shares: `earned = pending + (shares × (rpt − rptPaid)) / PRECISION`, where `PRECISION` is the contract constant `u1000000000000000000`.
53+
54+
For a single member's position rather than the pool's, use `get-earned-staker-rewards`, which takes a staker principal as well. Reward claims run through `claim-rewards`, called by your contract, and `claim-staker-rewards-for-signer` marks an individual member settled.
55+
56+
### SDK equivalents
57+
58+
The three signer-side reads are wrapped in `@stacks/bitcoin-staking` 7.6.0:
59+
60+
| Function | Wraps |
61+
| ----------------------------------- | ------------------------------------------------ |
62+
| `fetchEarned` | `get-earned` |
63+
| `fetchSignerUnclaimedRewards` | `get-signer-unclaimed-rewards-for-cycle` |
64+
| `fetchSignerRewardsPerTokenSettled` | `get-signer-rewards-per-token-settled-for-cycle` |
65+
66+
All three take `{ signerManager, rewardCycle, bondIndex? } & NetworkClientParam`. Omit `bondIndex` for the STX-only leg; pass it for a bond leg.
67+
68+
The staker-side variants are **separate functions**, and this is the distinction that costs people time: `fetchEarnedStakerRewards`, `fetchStakerUnclaimedRewards`, and `fetchStakerRewardsPerTokenSettled`, which additionally require `staker`. As the pool operator you read the signer-side figures. A pool member reads the staker-side ones. Label which is which wherever your interface shows a balance.
69+
70+
## Escape hatches
71+
72+
### `update-bond-registration`
73+
74+
Rotate the pool to a new signer-manager mid-bond. Reverts with `ERR_UPDATE_BOND_SAME_SIGNER u44` if the signer-manager passed is the one already in place, and is rejected during the prepare phase with `ERR_STAKE_IN_PREPARE_PHASE u47`. The new signer-manager needs a live signer key grant, or `ERR_SIGNER_KEY_GRANT_NOT_FOUND u17`.
75+
76+
It settles rewards with both the old and the new signer and moves shares between them. The change takes effect from the next reward cycle, or from the bond's start cycle if the bond has not begun.
77+
78+
Positions and term are unaffected. This changes who manages, not what is locked.
79+
80+
### `unstake-sbtc`
81+
82+
Withdraw locked sBTC, in full or in part, with no bond-deadline restriction. That is unlike L1-locked participants, who are bound by their CLTV and must use the early-exit path instead.
83+
84+
Four conditions still apply:
85+
86+
* **Rejected during the prepare phase**, with `ERR_STAKE_IN_PREPARE_PHASE u47`. "At any time" does not include the last 100 Bitcoin blocks of a cycle.
87+
* The membership must not be an L1 lock, or `ERR_CANNOT_UNSTAKE_SBTC u38`.
88+
* The signer-manager passed must match the current signer, or `ERR_INVALID_OLD_SIGNER_MANAGER u36`.
89+
* The amount cannot exceed the current stake, or `ERR_INVALID_UNSTAKE_SBTC_AMOUNT u37`.
90+
91+
The staker is taken from `tx-sender` rather than passed as an argument, so your contract must be the direct caller and it withdraws the pool's own position. There is no path by which pox-5 withdraws on behalf of an individual member: member exits are your contract's problem, settled against the pool's aggregate position.
92+
93+
`unstake-sbtc` reads `protocol-bond-memberships` directly, rather than through the expiry-filtered `get-bond-membership` that `update-bond-registration` uses. So it still works after the bond's term ends, while `update-bond-registration` returns `ERR_NOT_BOND_PARTICIPANT u34`. That is your route to retrieving pooled sBTC after a bond closes.
94+
95+
The sBTC transfer goes to the caller via the hardcoded mainnet token principal `SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token`.
96+
97+
### Rolling the pool forward
98+
99+
Rather than withdrawing and re-registering, call `register-for-bond` again for a later bond. The contract transfers only the net sBTC difference between the two positions, so a pool rolling into a same-size bond moves no sBTC at all.
100+
101+
This is allowed only once the old bond's L1 unlock height is reached, which is half a reward cycle before its L2 end. Earlier gives `ERR_ROLLOVER_TOO_EARLY u48`. Overlapping terms give `ERR_ALREADY_REGISTERED u9`.
102+
103+
## Related reading
104+
105+
* [Bitcoin Staking Glossary](https://docs.stacks.co/learn/bitcoin-staking/glossary)
106+
* [Protocol Bond and Rewards Mechanics](https://docs.stacks.co/learn/bitcoin-staking/rewards-and-tranches)
107+
* [What's changed in PoX-5](../staking-stx/whats-changed-in-pox-5.md)
108+
109+
## Sources
110+
111+
Every contract-level claim on this page is checked against the pinned release and the deployed contract:
112+
113+
* [`pox-5.clar` at tag 4.0.1](https://github.com/stacks-network/stacks-core/blob/4.0.1/stackslib/src/chainstate/stacks/boot/pox-5.clar)
114+
* [`SP000000000000000000002Q6VF78.pox-5` on mainnet](https://explorer.hiro.so/txid/SP000000000000000000002Q6VF78.pox-5?chain=mainnet\&tab=sourceCode)
115+
116+
The roughly-10% community carve-out is Endowment allocation policy and has no contract representation. The SDK names come from `@stacks/bitcoin-staking` 7.6.0, not from pox-5.

0 commit comments

Comments
 (0)