Skip to content

Conversation

@friedger
Copy link
Contributor

@friedger friedger commented Apr 4, 2025

This PR adds a SIP specifying

  • how to remove the cooldown cycle.
  • how to streamline solo stacking and delegated stacking
  • how to improve the relationship between signers and stackers

@friedger friedger mentioned this pull request Apr 4, 2025
Copy link
Contributor

@314159265359879 314159265359879 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this Friedger! I look forward to the proposed changes going live.

Added some minor comments about typos.

In the SIP I would also like to read how a transition from PoX-4 to PoX-5 would influence the sBTC protocol and how potential risks or other complexities are mitigated and/or dealt with.

@friedger
Copy link
Contributor Author

There are still a few open design questions. Main discussion so far should happen on https://forum.stacks.org/t/remove-cool-down-cycle-in-stacking/17899/13

@friedger friedger marked this pull request as draft April 10, 2025 13:52
@friedger friedger marked this pull request as ready for review June 16, 2025 08:00
Copy link
Contributor

@314159265359879 314159265359879 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added a couple nits, mostly typos and two suggestion to improve clarity/readability.

@nieldeckx
Copy link

Really liking this upgrade!

One ask from StackingDAO: please give plenty of time before the PoX-5 change goes live. We’ll need to update our code and get an audit, which takes a while. A clear schedule for testnet and mainnet would be nice.

@friedger friedger changed the title Improved stacking SIP-32: Improved stacking Aug 14, 2025
@friedger friedger changed the title SIP-32: Improved stacking SIP-032: Improved stacking Aug 14, 2025

- stack-stx
- stack-increase
- stack-extend
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of removing them, could they instead wrap calls to the delegation functions? For example, stack-stx could be re-implemented to delegate STX to the caller, and have the caller stack and aggregate-commit them.


- `LockingLimit(PostConditionPrincipal, FungibleConditionCode, u64)`

A transaction (using Deny mode) with this post condition will abort if the locked Stacks tokens of the principal do not satisfy the provided conditions. The logic for the conditions follows that of STX transfer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the order in which this SIP and the Clarity 4 SIP (#218) get ratified, it may be useful for #218 to add an asset guard special form for PoX locking (cc @obycode).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. I had that thought at some point, but then forgot to include it. Thanks! I'll add it.


The amount of stacked STX does not decrease during the automatic extension. If the user requested a decrease of the stacked amount, this difference is unlocked at the end of the stacking period.

## Semantic Change of Delegation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm generally fine with renaming things. Would it also be possible to preserve the existing function names and signatures, and have them call the new functions? The reasoning here is that it would keep existing tool and scripts working.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for backwards compatibility here


When signers verify and accept proposed blocks by miners, their voting power corresponds to the amount of stacked Stacks tokens (see SIP-021). The new stacking process changes the delegation flow as follows:

- `delegate-stx` shall be renamed to `designate`. The function takes the arguments: `amount`, `signature`, optional bitcoin `block-height` defining the end of stacking and auto extending, optional `pox-addr` defining that pox-address that the signer must use, optional `max-amount`. The `amount` defines how many Stacks tokens are locked immediately. The `max-amount` defines the maximum of Stacks tokens that can be locked in the future through auto extending. If provided the minimum of the user's stx balance and `max-amount` is locked. If omitted, the whole user's balance is locked. Users can use sponsored transactions to call revoke-delegate-stx in case there is no unlocked stx in the account. The argument `signature` is a signature of the signer indicating that the signer accepted the delegation of voting power. The signing follows the structured message signing with the parameters and topic `designate` as message. The public key of the signature can be used to identify the signer similar to the Stacks address of the pool operator in the previous PoX design.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the function signature?

(define-public (designate
   ;; The amount of uSTX to be locked immediately
   (amount uint)
   ;; Signature of the signer indicating that the signer accepted the delegation of voting power
   (signature (buff 65))
   ;; The Bitcoin block height at which this designation ends, if any.
   ;; N.B. the text says `block-height`, but this is a reserved word.
   ;; I'm using `end-block-height` in its place.
   (end-block-height (optional uint))
   ;; PoX address that the signer must use, to which PoX yield accrues
   (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) }))
   ;; Maximum amount of uSTX that can be locked through future auto-extending
   (max-amount (optional uint))
   
   ;; code goes here
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few other questions:

  • Can you describe the SIP-018 payload that must be signed by the signer?
  • How does this method identify the signer public key to use, in order to authenticate signature? Can it be an argument to the function, like it is for stack-aggregation-commit and stack-aggregation-increase?
  • How does this method ensure that signatures cannot be reused? The current PoX code uses an auth-id, which must be included in the signature and which cannot be re-used across signatures from the same signer key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signatures should be created in the same way as Pox-4 using public key and auth-id, etc. I'll extend the section about signatures.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be best to include the actual function signature in the SIP. Additionally, we will need signer-key as an argument


## Amount of Stacked STX

When a transaction locks or unlocks STX for the user a corresponding event shall be emitted. The following events used in PoX 4 are used:
Copy link
Contributor

@jcnelson jcnelson Aug 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PoX 4 uses the function's name as the event's name (i.e. in the event tuple's name field). Is this mapping from a PoX 5 event to the old PoX 4 event correct?

  • designate --> delegate-stx
  • designate-increase --> stacks-aggregation-increase
  • designate-decrease --> (this is new, and has no PoX 4 analogue)
  • designate-extend --> similar to delegate-stx-extend, but is now automatic?
  • signer-accept --> stacks-aggregation-commit

Can you also explain what the event payloads will be?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see that stacks-aggregate-commit is due to be replaced with signer-register. Is signer-accept a new function in PoX 5? I don't see it defined in this document.

Copy link
Contributor Author

@friedger friedger Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signer-accept is defined in ## Amount of Stacked STX as event name. The function is signer-register.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, I'll change signer-accept to a function name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The events in Pox 5 are similar (-->) in Pox 4

  • designate --> delegate-stx + delegate-stx-stack
  • designate-increase --> delegate-stx-increase but by user
  • designate-decrease --> (this is new, and has no PoX 4 analogue)
  • designate-extend --> similar to delegate-stx-extend, but is now automatic? Correct, however, there is no call from the user
  • signer-accept --> stacks-aggregation-commit

Payloads should be similar to pox-4, I'll spend some time to specify them as well.

2. one for delegation approval and register transactions on the Stacks blockchain;
3. optionally, one for PoX reward address and reward distribution.

Note, for solo Stackers these keys can be just a single key. For more complex setup, the keys can be handled by different independent entities. Also, the PoX reward address can be a deposit address for sBTC of a Stacks smart contract. In this case, the signer does not hold a private key for the PoX reward address.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all likelihood, solo stackers also have separate keys for signing, for cold storage STX, and for Bitcoin rewards.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the PoX reward address can be a deposit address for sBTC of a Stacks smart contract.

This is very interesting. Is the taproot address guaranteed to be stable for long enough that it can be used as a PoX address? My understanding of the sBTC minting process is as follows:

  • The user creates a taproot address from two scripts -- a deposit script, and a reclaim script
    • The deposit script contains the WSTS aggregate public key's X coordinate, the maximum BTC fee, and the Stacks principal to which to mint the sBTC (it's <[8-byte-max-fee][up-to-159-byte-SIP-005-principal]> OP_DROP <signers-x-public-key> OP_CHECKSIG).
    • The reclaim script, which allows the sender to reclaim the BTC after a timeout (it's <locktime> OP_CSV <user-supplied-reclaim-script>).
  • The user creates a Bitcoin transaction which sends BTC to the taproot address
  • The user informs the Emily API service of the transaction
  • The Emily API service forwards the transaction to the sBTC signers
  • The sBTC signers, if possible, will spend the taproot UTXO via the deposit script. If the signers can't do this in time, then the user can spend it with the reclaim script.

The risk to users in supplying an sBTC deposit taproot address is that their maximum fee value and locktime value will need to remain set for at least one stacking cycle. The user would need to change their PoX address each time they want to change the maximum fee or advance the locktime. Can this SIP advise users on how to construct their sBTC deposit addresses for them to be suitable for their desired number of reward cycles?

Copy link
Contributor Author

@friedger friedger Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all likelihood, solo stackers also have separate keys for signing, for cold storage STX, and for Bitcoin rewards.

I inserted "theoretically".

Also, the PoX reward address can be a deposit address for sBTC of a Stacks smart contract.

My intention was to highlight that this is possible with the new setup. However, explaining details how to implement this, should be part of a different resource, e.g. https://github.com/friedger/clarity-trustless-pool/

@friedger
Copy link
Contributor Author

@jcnelson I am hesitant to keep the old functions and signatures. It might be confusing to mix the different semantics.


When signers verify and accept proposed blocks by miners, their voting power corresponds to the amount of stacked Stacks tokens (see SIP-021). The new stacking process changes the delegation flow as follows:

- `delegate-stx` shall be renamed to `designate`. The function takes the arguments: `amount`, `signature`, optional bitcoin `block-height` defining the end of stacking and auto extending, optional `pox-addr` defining that pox-address that the signer must use, optional `max-amount`. The `amount` defines how many Stacks tokens are locked immediately. The `max-amount` defines the maximum of Stacks tokens that can be locked in the future through auto extending. If provided the minimum of the user's stx balance and `max-amount` is locked. If omitted, the whole user's balance is locked. Users can use sponsored transactions to call revoke-delegate-stx in case there is no unlocked stx in the account. The argument `signature` is a signature of the signer indicating that the signer accepted the delegation of voting power. The signing follows the structured message signing with the parameters and topic `designate` as message. The public key of the signature can be used to identify the signer similar to the Stacks address of the pool operator in the previous PoX design.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be best to include the actual function signature in the SIP. Additionally, we will need signer-key as an argument


When signers verify and accept proposed blocks by miners, their voting power corresponds to the amount of stacked Stacks tokens (see SIP-021). The new stacking process changes the delegation flow as follows:

- `delegate-stx` shall be renamed to `designate`. The function takes the arguments: `amount`, `signature`, optional bitcoin `block-height` defining the end of stacking and auto extending, optional `pox-addr` defining that pox-address that the signer must use, optional `max-amount`. The `amount` defines how many Stacks tokens are locked immediately. The `max-amount` defines the maximum of Stacks tokens that can be locked in the future through auto extending. If provided the minimum of the user's stx balance and `max-amount` is locked. If omitted, the whole user's balance is locked. Users can use sponsored transactions to call revoke-delegate-stx in case there is no unlocked stx in the account. The argument `signature` is a signature of the signer indicating that the signer accepted the delegation of voting power. The signing follows the structured message signing with the parameters and topic `designate` as message. The public key of the signature can be used to identify the signer similar to the Stacks address of the pool operator in the previous PoX design.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally understand the usage of max-amount here, but this differs from the current usage of max-amount. Currently, max-amount is used for the signer to say "you can't stack any more than this, because I don't want to have too much signing power". In this proposal, max-amount is for the stacker to say "you can only lock at most this much".

These are two different things, so we'll need to reconcile this fact. Either we add a new argument for the stacker's intention, or we remove the current usage of max-amount.

Additionally, from a UX perspective, we need to think about how max-amount is used in signature generation. When referring to the stacker's intention of "you can only lock at most X", we should probably just omit it from signature generation. Otherwise, signers will need to get this information ahead of time for generating signatures.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After further consideration, I think we need to keep both the old param and the new param, meaning we need to figure out what to call these params. My recommendation is:

  • max-amount: the same as before. This represents "the max amount a signer will allow a stacker to stack towards their signer key". For most signers, this will remain u128::max
  • allowance: the maximum amount that a stacker is allowing the signer to stack.

This would essentially mean replacing "max-amount" with "allowance" in this paragraph.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After further reading, I actually don't understand what max-amount means here. If I call designate with an amount of 1000, and a max-amount of 2000, what happens? It doesn't seem like signer-accept takes an amount or anything, so where does max-amount ever come into play?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated this section to clarify what it means when max-amount is omitted. In this case, amount is used as max-amount.

I also renamed max-amount to amount-allowance to avoid confusion about max-amount used during signature generation.

max-amount/amount-allowance is used during auto-extend where the stacking amount can be increased automatically as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants