Skip to content

Commit bbe72b0

Browse files
werner-stacksgitbook-bot
authored andcommitted
GITBOOK: Protocol Bonds: add Verifying and Reclaiming Your Locked Bitcoin; renewal on the ending page; lock-s
1 parent 7e1bd8a commit bbe72b0

5 files changed

Lines changed: 117 additions & 1 deletion

File tree

‎docs/operate/SUMMARY.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@
3737
* [Getting Allowlisted for a Bond](protocol-bonds/getting-allowlisted-for-a-bond.md)
3838
* [Bond Pool (BTC + STX) Operator Guide](protocol-bonds/bond-pool-operator-guide.md)
3939
* [Opening a Bond Position](protocol-bonds/opening-a-bond-position.md)
40+
* [Verifying and Reclaiming Your Locked Bitcoin](protocol-bonds/verifying-and-reclaiming-your-locked-bitcoin.md)
4041
* [Ending or Changing a Bond Position](protocol-bonds/ending-or-changing-a-bond-position.md)

‎docs/operate/protocol-bonds/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ A protocol bond pairs a Bitcoin commitment with an STX lock for a 12-cycle term.
1010

1111
* [Getting Allowlisted for a Bond](getting-allowlisted-for-a-bond.md): how capacity is allocated, what to send the Stacks Endowment, and how to check your entry.
1212
* [Opening a Bond Position](opening-a-bond-position.md): the allowlist, the two Bitcoin legs, the registration deadline, and what the contract checks.
13+
* [Verifying and Reclaiming Your Locked Bitcoin](verifying-and-reclaiming-your-locked-bitcoin.md): checking the lock address before funding, what you need to spend it later, and reclaiming after the timelock.
1314
* [Ending or Changing a Bond Position](ending-or-changing-a-bond-position.md): exiting early, withdrawing sBTC, changing signer-manager, and rolling into a new position.
1415
* [Bond pool operator guide](bond-pool-operator-guide.md): running a whitelisted community sBTC pool.
1516

‎docs/operate/protocol-bonds/ending-or-changing-a-bond-position.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ What each route does with your assets:
118118

119119
Because your STX is still locked by the ending position, both functions check your locked plus unlocked balance rather than unlocked alone. A bond and an STX-only stake can never both be live, which is why moving between them happens at a boundary rather than mid-term.
120120

121+
### Renewing a native BTC bond
122+
123+
Renewing means registering for the next bond before yours ends, so you move straight from one into the next. The first bond that does not overlap yours starts when yours ends, six bond indexes later.
124+
125+
1. **Get allowlisted for the new bond.** Each bond has its own allowlist, and being on the current one does not carry over. See [Getting Allowlisted for a Bond](getting-allowlisted-for-a-bond.md).
126+
2. **Lock BTC for the new bond.** Either fund its lock address from other BTC ahead of time, or wait until your current output's unlock height and spend that output straight into the new lock address. The second needs no other BTC. See [Verifying and Reclaiming Your Locked Bitcoin](verifying-and-reclaiming-your-locked-bitcoin.md).
127+
3. **Register once the new lock confirms**, after your bond's L1 unlock height and before the prepare phase that precedes its end. You can change the STX amount. It must meet the new bond's minimum, and your STX that is still locked counts toward your balance.
128+
129+
On testnet the window is half a testnet reward cycle, 525 blocks, of which 475 are usable.
130+
131+
If you do not register in time, your bond ends normally: your STX unlocks at the end of the term and your BTC stays spendable by you through the timelock branch. You can still join a later bond as a new registration.
132+
121133
## Prepare-phase timing
122134

123135
`register-for-bond`, `update-bond-registration`, `stake`, `stake-update`, `announce-l1-early-exit`, and `unstake-sbtc` share one guard and one error, `ERR_STAKE_IN_PREPARE_PHASE (u47)`. `unstake` has its own check and code, `ERR_UNSTAKE_IN_PREPARE_PHASE (u28)`.

‎docs/operate/protocol-bonds/opening-a-bond-position.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Read your cap for the bond. A missing entry means you are not allowlisted.
5555
The address is deterministic: it comes from your Stacks address, the bond's unlock height, your `staker-unlock-bytes`, and the bond's `early-unlock-bytes`. Anyone can rederive it to check the lock.
5656

5757
{% hint style="danger" %}
58-
**Keep your unlock bytes.** The `staker-unlock-bytes` are not stored on-chain. Without them the lock address cannot be rebuilt and the BTC cannot be reclaimed by either path.
58+
**Keep your lock script.** The contract does not store your `staker-unlock-bytes` or the lock script built from them, so save the lock script when you register. If you lose it, rebuild it from your `register-for-bond` transaction. See [Verifying and Reclaiming Your Locked Bitcoin](verifying-and-reclaiming-your-locked-bitcoin.md).
5959
{% endhint %}
6060
{% endstep %}
6161

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
description: >-
3+
How to check a bond's Bitcoin lock address before you fund it, what you need
4+
to spend it later, and how to reclaim your BTC once the timelock passes.
5+
---
6+
7+
# Verifying and Reclaiming Your Locked Bitcoin
8+
9+
On a native BTC bond your Bitcoin stays in an output you control, guarded by a timelock. This page covers the two moments that matter for your funds: checking the lock address before you send anything to it, and spending the output back to yourself once the timelock passes. For leaving before the timelock, see [Ending or Changing a Bond Position](ending-or-changing-a-bond-position.md).
10+
11+
## Before you fund: check the lock address
12+
13+
The lock address is deterministic. It is built from four inputs:
14+
15+
* your Stacks address,
16+
* the output's unlock height, at or above the bond's minimum,
17+
* your `staker-unlock-bytes`, by default `<your Bitcoin public key> OP_CHECKSIG`,
18+
* the bond's `early-unlock-bytes`, published on-chain when the bond is set up.
19+
20+
Check the address against the contract before funding. The contract's `construct-lockup-output-script` builds the same output from the same inputs. If it disagrees with the address your wallet or tool shows, do not fund. The code is under [Cross-check the script before funding](verifying-and-reclaiming-your-locked-bitcoin.md#cross-check-the-script-before-funding).
21+
22+
{% hint style="danger" %}
23+
**Check before you send.** BTC sent to an address that does not match the contract's script cannot be registered for the bond, and whether you can spend it depends entirely on what that address actually encodes.
24+
{% endhint %}
25+
26+
## What you need to spend it later
27+
28+
Spending the output needs the lock script, the output itself, and your Bitcoin key. Save the lock script when you register, and keep the lock transaction ID: it identifies the output to spend. If you lose the lock script, you can rebuild it from its four inputs:
29+
30+
| Input | Where to find it again |
31+
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
32+
| Stacks address | Your Stacks wallet |
33+
| Unlock height | The arguments of your `register-for-bond` transaction |
34+
| `staker-unlock-bytes` | The same transaction. With the default unlock bytes, rebuild them from the public key of the Bitcoin key you registered with |
35+
| `early-unlock-bytes` | The bond's on-chain record |
36+
37+
The contract keeps none of these in its own state, which is why the registration transaction matters.
38+
39+
## Reclaim after the timelock
40+
41+
Once Bitcoin passes the output's unlock height, you spend it alone through the timelock branch. There is no co-signer, no Stacks transaction and no deadline: the output stays spendable by you from then on.
42+
43+
Your STX leg unlocks separately, at the end of the bond term on Stacks. See the [bond timeline](https://docs.stacks.co/learn/bitcoin-staking#the-bond-timeline).
44+
45+
## Building a reclaim
46+
47+
For wallet, custodian, and app developers. The examples use [`@stacks/bitcoin-staking`](https://www.npmjs.com/package/@stacks/bitcoin-staking) 7.6.0.
48+
49+
### Cross-check the script before funding
50+
51+
```ts
52+
import { buildLockOutputScript, fetchConstructLockupOutputScript } from '@stacks/bitcoin-staking';
53+
import { bytesToHex } from '@stacks/common';
54+
55+
const inputs = { stxAddress: staker, unlockHeight, unlockBytes, earlyUnlockBytes: bond.earlyUnlockBytes };
56+
57+
const local = buildLockOutputScript(inputs);
58+
const onchain = await fetchConstructLockupOutputScript({ ...inputs, network: 'mainnet' });
59+
if (bytesToHex(local) !== bytesToHex(onchain)) {
60+
throw new Error('Lock script mismatch: do not fund');
61+
}
62+
```
63+
64+
### Rebuild the lock script if you did not keep it
65+
66+
```ts
67+
import { buildLockScript, buildUnlockScript, fetchBond } from '@stacks/bitcoin-staking';
68+
69+
const bond = await fetchBond({ bondIndex, network: 'mainnet' });
70+
const lockScript = buildLockScript({
71+
stxAddress: staker,
72+
unlockHeight, // from your register-for-bond transaction
73+
unlockBytes: buildUnlockScript(stakerBtcPublicKey),
74+
earlyUnlockBytes: bond.earlyUnlockBytes,
75+
});
76+
```
77+
78+
### Build, sign and finalize the spend
79+
80+
```ts
81+
import { buildReclaim, finalizeReclaim } from '@stacks/bitcoin-staking';
82+
83+
const tx = buildReclaim({
84+
path: 'locktime',
85+
utxo, // the lockup UTXO: { txid, vout, value }
86+
lockScript,
87+
output: { address: destinationAddress, feeSats },
88+
network: 'mainnet',
89+
});
90+
91+
// Sign input 0 with your key, or send tx.toPSBT() to a hardware or browser wallet
92+
tx.signIdx(stakerPrivateKey, 0);
93+
94+
const { txHex, txid } = finalizeReclaim({ path: 'locktime', tx });
95+
// Broadcast txHex to Bitcoin
96+
```
97+
98+
`buildReclaim` sets the transaction's `nLockTime` to the unlock height decoded from the lock script, so the spend can be mined from the block after that height. The signature commits to the outputs and fee, so set them before signing.
99+
100+
### Relock straight into the next bond
101+
102+
To renew without other BTC, set `output.address` to the next bond's lock address instead of your own. The same spend moves your BTC from the old lock into the new one. Once it confirms, register for the next bond with a proof of the new output. See [Renewing a native BTC bond](ending-or-changing-a-bond-position.md#renewing-a-native-btc-bond).

0 commit comments

Comments
 (0)