You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 956adf9
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/operate/deploy-a-signer-manager-contract.md
+151-3Lines changed: 151 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ description: >-
7
7
# Deploy a Signer Manager Contract
8
8
9
9
{% hint style="info" %}
10
-
All Clarity references on this page are pinned to [`pox-5.clar` at `stacks-core` 4.0.1](https://github.com/stacks-network/stacks-core/blob/4.0.1/stackslib/src/chainstate/stacks/boot/pox-5.clar) and to a [pinned mainnet build of the reference signer-manager](https://github.com/stx-labs/signer-sidekick/blob/214c67eae2f1ce1c3c818ab6528ce4f2e1bdc22a/contracts/reference-manager/generated/mainnet/signer-manager.clar).
10
+
All Clarity references on this page are pinned to [`pox-5.clar` at `stacks-core` 4.0.1](https://github.com/stacks-network/stacks-core/blob/4.0.1/stackslib/src/chainstate/stacks/boot/pox-5.clar) and to a [pinned mainnet build of the reference signer-manager](https://github.com/stx-labs/signer-sidekick/blob/11f8ff79e309db14357c4adfbbe31e1aeb7cd17e/contracts/reference-manager/generated/mainnet/signer-manager.clar).
11
11
{% endhint %}
12
12
13
13
### Who needs this page
@@ -68,10 +68,14 @@ Your contract must also gate `validate-stake!` so only pox-5 can call it. The re
68
68
69
69
### Deploy your contract
70
70
71
-
Deploy a Clarity contract implementing `signer-manager-trait`. The [pinned mainnet reference manager](https://github.com/stx-labs/signer-sidekick/blob/214c67eae2f1ce1c3c818ab6528ce4f2e1bdc22a/contracts/reference-manager/generated/mainnet/signer-manager.clar) is the recommended starting point. It is generated for mainnet, so its pox-5 and sBTC principals are already correct.
71
+
Deploy whichever signer-manager you have reviewed. The [reference implementation](https://github.com/stx-labs/signer-sidekick/blob/11f8ff79e309db14357c4adfbbe31e1aeb7cd17e/contracts/reference-manager/generated/mainnet/signer-manager.clar) is the recommended starting point today, and more will follow, including [one with a lower fee ceiling](https://explorer.hiro.so/txid/SPMPMA1V6P430M8C91QS1G9XJ95S59JS1TZFZ4Q4.fastpool-max500-signer-manager?chain=mainnet\&tab=sourceCode) (`MAX_FEE_BIPS u500`).
72
+
73
+
The fee ceiling and the admin model are properties of the contract you deploy, not of pox-5, and they cannot be changed afterwards.
74
+
75
+
Mainnet and testnet builds are not interchangeable. The embedded pox-5 boot principal and the sBTC contract addresses differ, so a mainnet build fails analysis on testnet.
72
76
73
77
{% hint style="danger" %}
74
-
Do not deploy the `stacks-core` test fixture under `contrib/core-contract-tests/`. Its pox-5 and sBTC principals do not match mainnet. Verify the canonical hash of whatever source you deploy against the expected value before broadcasting, and confirm the deployed principal on-chain afterwards. A transaction ID confirms submission, not success.
78
+
Do not deploy the `stacks-core` test fixture under `contrib/core-contract-tests/`. Its pox-5 and sBTC principals do not match mainnet. Confirm the deployed principal on-chain afterwards. A transaction ID confirms submission, not success.
75
79
{% endhint %}
76
80
77
81
The reference manager's deployer becomes its first admin automatically (`(map-set admins tx-sender true)`).
@@ -82,6 +86,150 @@ The reference manager's deployer becomes its first admin automatically (`(map-se
82
86
Ledger Stacks App versions through `0.26.17` cannot sign a deployment payload that carries an explicit Clarity version, so leave any "force Clarity 6 payload" option switched off. With the version omitted, the node defaults the contract to Clarity 6, which it does since Epoch 4.0 activated. The Leather extension omits the version for you from version `6.107.0` onward. Stacks App `0.27.x` is expected to remove the restriction.
83
87
{% endhint %}
84
88
89
+
### How to deploy with stacks-cli
90
+
91
+
`stacks-cli` is the binary from `stacks-core`. It ships in the node image alongside `stacks-signer`, so there is nothing to build.
92
+
93
+
You need a reviewed signer-manager `.clar` file, a hot key to deploy with, and a cold key to hand admin control to. **Fund the cold key too**: it signs the last step and pays that fee itself.
94
+
95
+
The CLI cannot sign with a hardware wallet or a multisig, so the deploying key is always hot and the rotation in steps 4 and 5 is part of the deployment rather than an optional hardening pass.
96
+
97
+
Examples use `docker`. For Fedora, RHEL and immutable Linux, see the note at the end of this section.
`read -rs` takes the key without echoing it and keeps it out of shell history.
107
+
108
+
Both variables live only in the current shell. Re-run this block in a new terminal. If you forget, the failure gives no hint: with `$IMG` empty, the runtime reads the next word as the image name and reports `short-name resolution enforced but cannot prompt without a TTY`.
109
+
110
+
#### How broadcasting works
111
+
112
+
Every command below writes a signed transaction as hex to stdout and stops. The CLI never broadcasts. Each step therefore ends the same way:
Output is JSON containing `signerKey`, `signerSignature` and `authId`. It contains no private key, which is what makes it safe to move to wherever you build the next transaction.
147
+
148
+
`auth-id` is a replay guard. The tuple of signer key, signer manager and auth-id can be consumed once.
149
+
150
+
**The grant is bound to the network in your config.** There is no chain-id flag; it comes from the `network` field. A grant generated against the wrong network aborts at the next step with `ERR_INVALID_SIGNATURE_PUBKEY (u14)`, which reads as a wrong-key problem and sends you looking in the wrong place.
151
+
152
+
#### 3. Register the manager against the signer key
153
+
154
+
Admin-only, so run it while the deploying key is still the admin. The three values come from step 2.
155
+
156
+
```bash
157
+
docker run --rm -e STX_SK $IMG \
158
+
stacks-cli contract-call "$STX_SK"<fee><nonce> \
159
+
<deployer-address><contract-name> register-self \
160
+
-e \'<deployer-address>.<contract-name> \
161
+
-e 0x<signerKey> \
162
+
-e u<authId> \
163
+
-e 0x<signerSignature>> tx.hex
164
+
```
165
+
166
+
The first argument is a trait reference, passed as the contract's own principal.
167
+
168
+
#### 4. Add the cold admin, from the hot deploy key
169
+
170
+
```bash
171
+
docker run --rm -e STX_SK $IMG \
172
+
stacks-cli contract-call "$STX_SK"<fee><nonce> \
173
+
<deployer-address><contract-name> update-admin \
174
+
-e \'SP<COLD-ADMIN-PRINCIPAL> -e true> tx.hex
175
+
```
176
+
177
+
Arguments come in flag and value pairs, `-e` to evaluate or `-x` for a hex-serialized Clarity value. The backslash-escaped apostrophe is the form the tool's own help uses for a principal literal.
178
+
179
+
#### 5. Remove the hot key, from the cold admin
180
+
181
+
Load the cold key into `STX_SK` and repeat with `false`. This proves the cold key can sign and retires the hot key in one call.
182
+
183
+
```bash
184
+
docker run --rm -e STX_SK $IMG \
185
+
stacks-cli contract-call "$STX_SK"<fee><nonce> \
186
+
<deployer-address><contract-name> update-admin \
187
+
-e \'SP<HOT-DEPLOYER-PRINCIPAL> -e false> tx.hex
188
+
```
189
+
190
+
**Keep the signer key.** Rotating admin does not transfer everything. Revoking a grant is authorised by the signer key, not by admin status, so a cold admin cannot revoke.
191
+
192
+
There is no on-chain guard against removing the last admin. `(update-admin tx-sender false)` as the only admin permanently bricks every admin function, including `withdraw-fees`, and any accrued sBTC becomes unreachable. The ordering above is what protects against it: a wallet that is not an admin fails with `ERR_UNAUTHORIZED_ADMIN (u1002)` and changes nothing, so whoever succeeds at the removal is demonstrably not the last admin.
193
+
194
+
#### Revoking, from the CLI
195
+
196
+
Not part of setup. This call goes to `pox-5`, not to your manager, and is authorised by the signer key rather than by admin status.
Argument order is `signer-manager` then `signer-key`, the reverse of `grant-signer-key`. Getting it backwards aborts with `ERR_UNAUTHORIZED (u1)`, which looks like a permissions problem.
207
+
208
+
**The registration is expected to persist.**`get-signer-info` still resolves your manager to that signer key after a successful revoke. Check grant state, not registration. See [Revoke a grant](deploy-a-signer-manager-contract.md#revoke-a-grant-revoke-signer-grant) below for why.
209
+
210
+
#### On Fedora, RHEL and immutable Linux
211
+
212
+
Substitute `podman` for `docker`. The commands are otherwise identical, with one exception.
213
+
214
+
SELinux relabels bind mounts, so the two steps that mount a file, the deploy and the grant, need `z`:
215
+
216
+
```bash
217
+
podman run --rm -e STX_SK -v ./signer-manager.clar:/tmp/sm.clar:ro,z $IMG \
Without it the container cannot read the file and the tool reports `IO error reading CLI input: Permission denied (os error 13)`.
222
+
223
+
#### Which key does which call
224
+
225
+
`register-self`, `update-admin`, `update-fees`, `withdraw-fees` and `sweep-fee-refunds` are admin-gated. `revoke-signer-grant` is gated on the signer key. In a normal setup those are different keys and different people.
226
+
227
+
Admin calls cannot be proxied: `authorize-admin` asserts `contract-caller` equals `tx-sender`, so an admin action must be a direct top-level call from the admin principal. A CLI-signed transaction satisfies this; a call routed through another contract does not.
228
+
229
+
#### Why there is no Clarity version flag
230
+
231
+
`publish` emits payload type `0x01` with no version byte, and the node applies its current default, which is Clarity 6 since Epoch 4.0.
232
+
85
233
### Register the signer key: `register-signer`
86
234
87
235
After deployment, the signer-manager contract itself calls `pox-5::register-signer` to bind itself to a signer key.
Copy file name to clipboardExpand all lines: docs/operate/stacking-stx/generate-signer-signature.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,10 @@ PoX-5 uses a one-time **signer-key grant**. You generate one grant per signer-ma
14
14
15
15
The grant is what connects your signer node, the signer-manager contract that stakers stake to, and the pox-5 contract. Without an active grant, `stake` and every related call against your manager fails with `ERR_SIGNER_KEY_GRANT_NOT_FOUND` (u17).
16
16
17
+
{% hint style="info" %}
18
+
Doing the whole setup from the command line? [Deploy a Signer Manager Contract](../deploy-a-signer-manager-contract.md) runs this step in sequence with the deploy, registration and admin rotation.
19
+
{% endhint %}
20
+
17
21
### Generate the grant
18
22
19
23
Run this on the signer host, where the private key already lives:
Those two fields are the whole scope. A grant authorises a signer-manager and stands until you revoke it.
65
69
70
+
The `chain-id` in the domain comes from the `network` field in your signer config. A grant generated against the wrong network fails at `grant-signer-key` with `ERR_INVALID_SIGNATURE_PUBKEY` (u14), which reads as a wrong-key problem rather than a wrong-network one.
0 commit comments