Proof of Transfer (PoX)

By @stacks-corearrow-up-right

circle-info

Deployed contract page found herearrow-up-right.

Contract Summary

The PoX-4 (Proof of Transfer) contract is the core system contract that implements Stacks' consensus mechanism, enabling STX holders to lock their tokens and earn Bitcoin rewards. This is the fourth iteration of the PoX contract, featuring signer key authorizations, delegation improvements, and enhanced security mechanisms.

Key Features:

  • Stacking Operations - Lock STX tokens for 1-12 reward cycles to earn BTC rewards

  • Delegation System - Allow delegates to stack on behalf of multiple STX holders (pooling)

  • Signer Key Authorization - Cryptographic verification system for signer keys used in Nakamoto consensus

  • Partial Stacking & Aggregation - Pool smaller amounts to meet minimum stacking threshold

  • Flexible Reward Cycles - Dynamic stacking periods with extension and increase capabilities

  • Multi-Network Support - Separate configurations for mainnet and testnet operations

  • Contract Caller Allowances - Enable smart contracts to interact with stacking on behalf of users

What Developers Can Learn:

  • How to implement complex locking mechanisms with automatic unlock

  • Delegation patterns for pooled resource management

  • Cryptographic signature verification (secp256k1) for authorization

  • Managing state across reward cycles with maps and indexes

  • SIP-018 structured data signing implementation

  • Building upgradeable system contracts with versioning

  • Network-aware contract logic (mainnet vs testnet)



Function-by-Function Breakdown

Core Stacking Functions

stack-stx (amount-ustx uint) (pox-addr {...}) (start-burn-ht uint) (lock-period uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Locks STX for stacking by an individual, requiring a valid signer key authorization. Returns lock information including the stacker address, amount, signer key, and unlock height.

stack-extend (extend-count uint) (pox-addr {...}) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Extends an existing stacking lock by the specified number of reward cycles. Must be called before the current lock expires.

stack-increase (increase-by uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Increases the amount of STX locked in an existing stacking position. The additional STX must be available in the caller's balance.

Delegation Functions

delegate-stx (amount-ustx uint) (delegate-to principal) (until-burn-ht (optional uint)) (pox-addr (optional {...}))

Delegates stacking rights to another principal, allowing them to stack on behalf of the delegator. Optionally restricts to a specific PoX address and expiration.

revoke-delegate-stx

Revokes an active delegation, preventing the delegate from further stacking operations. Returns the last delegation state.

delegate-stack-stx (stacker principal) (amount-ustx uint) (pox-addr {...}) (start-burn-ht uint) (lock-period uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Called by a delegate to stack STX on behalf of a delegator. Requires valid delegation and signer key authorization.

delegate-stack-extend (stacker principal) (pox-addr {...}) (extend-count uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Extends a delegated stacking position by the specified number of reward cycles. Only callable by the current delegate.

delegate-stack-increase (stacker principal) (pox-addr {...}) (increase-by uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Increases the amount of STX in a delegated stacking position. Only callable by the current delegate.

Aggregation Functions (For Pool Operators)

stack-aggregation-commit (pox-addr {...}) (reward-cycle uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Commits partially stacked STX to a reward cycle, allocating a new PoX address slot. Returns true on success.

stack-aggregation-commit-indexed (pox-addr {...}) (reward-cycle uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Same as stack-aggregation-commit but returns the PoX address index for use with stack-aggregation-increase.

stack-aggregation-increase (pox-addr {...}) (reward-cycle uint) (reward-cycle-index uint) (signer-sig (optional (buff 65))) (signer-key (buff 33)) (max-amount uint) (auth-id uint)

Adds more STX to an existing PoX address that has already been committed. Requires the reward cycle index from a previous commit.

Signer Key Authorization Functions

set-signer-key-authorization (pox-addr {...}) (period uint) (reward-cycle uint) (topic (string-ascii 14)) (signer-key (buff 33)) (allowed bool) (max-amount uint) (auth-id uint)

Pre-authorizes a signer key for use in stacking operations without requiring a signature. Useful for multisig or programmatic stacking.

verify-signer-key-sig (pox-addr {...}) (reward-cycle uint) (topic (string-ascii 14)) (period uint) (signer-sig-opt (optional (buff 65))) (signer-key (buff 33)) (amount uint) (max-amount uint) (auth-id uint)

Read-only function that verifies a signer key signature or pre-authorization. Used by clients to validate before submitting transactions.

get-signer-key-message-hash (pox-addr {...}) (reward-cycle uint) (topic (string-ascii 14)) (period uint) (max-amount uint) (auth-id uint)

Generates the SIP-018 message hash used for signer key signature verification. Follows structured data signing standard.


Key Concepts

Proof of Transfer (PoX) Mechanism

PoX is Stacks' unique consensus mechanism where STX holders lock their tokens to support the network and earn Bitcoin rewards. The PoX-4 contract manages all stacking operations, reward cycle tracking, and BTC payout address registration.

Reward Cycles and Burn Heights

The contract operates on reward cycles (2100 Bitcoin blocks on mainnet, ~2 weeks). Key functions convert between burn heights and reward cycles, enabling precise timing of stacking operations and reward distribution.

Signer Key Authorization (SIP-018)

A cryptographic authorization system where stackers provide either a signature or pre-authorization for signer keys. The message hash follows SIP-018 structured data signing, preventing signature replay and ensuring keys are authorized for specific operations.

Delegation Architecture

Delegation allows pool operators to aggregate STX from multiple holders. The contract tracks delegation relationships, including optional PoX address restrictions and expiration heights, while preventing conflicts like double-stacking.

Partial Stacking and Aggregation

Pool operators can accept STX amounts below the minimum threshold through partial stacking. The partial-stacked-by-cycle map accumulates these amounts until a stack-aggregation-commit creates an official reward set entry.

Authorization Replay Prevention

Uses used-signer-key-authorizations map and unique auth-id values to prevent reusing signatures across multiple transactions. Each authorization can only be consumed once per topic, reward cycle, and period combination.


Understanding the functions & flows for stacking

Stacking is implemented as part of the .pox-4 smart contract. In this walkthrough, we'll cover the different stacking flows from start to finish, including descriptions of the various functions and errors, and when you might use/encounter them.

Rather than walking through the contract line by line, which you can do by simply reading the contract code and the comments, we'll instead explore it from the perspective of conducting stacking operations, including solo stacking, delegating, and running a pool.

Solo Stacking

Solo stacking is the least complex flow, and begins by calling the stack-stx function.

stack-stx

This function locks up the given amount of STX for the given lock period (number of reward cycles) for the tx-sender. Here's the full code for that function, then we'll dive into how it works below that.

First let's cover the needed parameters.

  • amount-ustx is the amount of STX you would like to lock, denoted in micro-STX, or uSTX (1 STX = 1,000,000 uSTX).

  • pox-addr is a tuple that encodes the Bitcoin address to be used for the PoX rewards, details below.

  • start-burn-ht is the Bitcoin block height you would like to begin stacking. You will receive rewards in the reward cycle following start-burn-ht. Importantly, start-burn-ht may not be further into the future than the current reward cycle, and in most cases should be set to the current burn block height.

  • lock-period sets the number of reward cycles you would like you lock your STX for, this can be between 1 and 12.

  • signer-sig is a unique generated signature that proves ownership of this signer.

  • signer-key is the public key of your signer.

  • max-amount sets the maximum amount allowed to be stacked during the provided stacking period.

  • auth-id is a unique string to prevent re-use of this stacking transaction.

circle-exclamation
chevron-rightSupported reward address typeshashtag

For the pox-addr field, the version buffer must represent what kind of bitcoin address is being submitted. These are all the possible values you can pass here depending on your address type:

The stack-stx function performs several checks including:

  • The start-burn-ht results in the next reward cycle

  • The function is being called by the tx-sender or an allowed contract caller

  • The tx-sender is not currently stacking or delegating

  • The tx-sender has enough funds

  • The given signer-key is valid, proving ownership

  • Stacking can be performed (amount meets minimum threshold, lock period and bitcoin address are valid)

Next the function registers the provided PoX address for the next reward cycle, assigns its specific reward slot, and adds it to the stacking-state map, which keeps track of all current stackers per reward cycle.

Finally it returns the lock-up information so the node can carry out the lock. This step is what actually locks the STX and prevents the stacker from using them on-chain.

From here, the locked STX tokens will be unlocked automatically at the end of the lock period. The stacker can also call stack-increase or stack-extend to increase the amount locked or extend the time.

Delegated Stacking

Delegated stacking is essentially a multi-step process where delegators give pool operators permission to lock STX on their behalf. The typical flow:

1

Delegator delegates their STX to a pool operator

The delegator calls delegate-stx to record that they delegate a given amount to a specific pool operator. This does not lock the STX — it only records the delegation permission.

2

Pool operator stacks delegated STX (partial)

The pool operator calls delegate-stack-stx for each delegator they will lock on behalf of. This marks those STX as partially stacked (not yet in the official reward set).

3

Pool operator commits aggregated locks

When the pool operator has aggregated enough delegated STX, they call stack-aggregation-commit-indexed (wraps inner-stack-aggregation-commit) to commit the aggregated stake into the reward set for the reward cycle.

delegate-stx

This function is called by the individual stacker delegating their STX to a pool operator. An individual stacker choosing to delegate does not need to run their own signer.

This function does not actually lock the STX, but just allows the pool operator to issue the lock.

Parameters:

  • amount-ustx: amount delegating (uSTX)

  • delegate-to: Stacks address of the pool operator

  • until-burn-ht: optional expiry burn height for the delegation

  • pox-addr: optional Bitcoin address where this delegator wants rewards sent (if supplied, pool operator must send rewards to this address)

Checks: caller allowed, pox-addr version valid if provided, delegator not already delegating. Updates delegation-state. No STX are locked yet — the pool operator must call delegate-stack-stx.

delegate-stack-stx

Called by the pool operator to partially stack a delegator's STX.

This function validates the delegation record, ensures the delegator has the funds and is not already stacking, runs lightweight stacking checks, registers the partial stacked amount, and updates stacking-state. The STX remain partially stacked until the operator commits.


How Stacking Reward Distribution Works

All of the above stacking functions take a pox-addr field that corresponds to a Bitcoin address where BTC rewards will be sent. It's important to understand how these addresses are used and how reward distribution is handled.

How Bitcoin rewards are distributed is primarily up to the discretion of the pool operator. Since PoX reward distributions are handled using Bitcoin transactions, there is currently not an effective way to automate their distribution to individual delegated stackers.

Role of pox-addr by function:

  • stack-stx: Bitcoin address for the solo stacker to receive rewards.

  • delegate-stx: Optional. If omitted, the pool operator decides where to send this delegator's rewards. If provided, the pool operator must send rewards to that address. Note: if provided, the delegator must have enough STX to meet the minimum stacking amount (each unique pox-addr consumes a reward slot).

  • delegate-stack-stx and stack-aggregation-commit-indexed: pox-addr is where the pool operator will receive BTC rewards for that aggregated stake. Pool operators typically use wrapper contracts or off-chain accounting to distribute BTC to delegators.

Last updated

Was this helpful?