pub const POX_CONTRACT: &'static str = ";; PoX testnet constants\n;; Min/max number of reward cycles uSTX can be locked for\n(define-constant MIN_POX_REWARD_CYCLES u1)\n(define-constant MAX_POX_REWARD_CYCLES u12)\n\n;; Default length of the PoX registration window, in burnchain blocks.\n(define-constant PREPARE_CYCLE_LENGTH u30)\n\n;; Default length of the PoX reward cycle, in burnchain blocks.\n(define-constant REWARD_CYCLE_LENGTH u150)\n\n;; Valid values for burnchain address versions.\n;; These correspond to address hash modes in Stacks 2.0.\n(define-constant ADDRESS_VERSION_P2PKH 0x00)\n(define-constant ADDRESS_VERSION_P2SH 0x01)\n(define-constant ADDRESS_VERSION_P2WPKH 0x02)\n(define-constant ADDRESS_VERSION_P2WSH 0x03)\n\n;; Stacking thresholds\n(define-constant STACKING_THRESHOLD_25 u480)\n(define-constant STACKING_THRESHOLD_100 u120)\n\n;; The .pox contract\n;; Error codes\n(define-constant ERR_STACKING_UNREACHABLE 255)\n(define-constant ERR_STACKING_INSUFFICIENT_FUNDS 1)\n(define-constant ERR_STACKING_INVALID_LOCK_PERIOD 2)\n(define-constant ERR_STACKING_ALREADY_STACKED 3)\n(define-constant ERR_STACKING_NO_SUCH_PRINCIPAL 4)\n(define-constant ERR_STACKING_EXPIRED 5)\n(define-constant ERR_STACKING_STX_LOCKED 6)\n(define-constant ERR_STACKING_PERMISSION_DENIED 9)\n(define-constant ERR_STACKING_THRESHOLD_NOT_MET 11)\n(define-constant ERR_STACKING_POX_ADDRESS_IN_USE 12)\n(define-constant ERR_STACKING_INVALID_POX_ADDRESS 13)\n(define-constant ERR_STACKING_ALREADY_REJECTED 17)\n(define-constant ERR_STACKING_INVALID_AMOUNT 18)\n(define-constant ERR_NOT_ALLOWED 19)\n(define-constant ERR_STACKING_ALREADY_DELEGATED 20)\n(define-constant ERR_DELEGATION_EXPIRES_DURING_LOCK 21)\n(define-constant ERR_DELEGATION_TOO_MUCH_LOCKED 22)\n(define-constant ERR_DELEGATION_POX_ADDR_REQUIRED 23)\n(define-constant ERR_INVALID_START_BURN_HEIGHT 24)\n\n;; PoX disabling threshold (a percent)\n(define-constant POX_REJECTION_FRACTION u25)\n\n;; Data vars that store a copy of the burnchain configuration.\n;; Implemented as data-vars, so that different configurations can be\n;; used in e.g. test harnesses.\n(define-data-var pox-prepare-cycle-length uint PREPARE_CYCLE_LENGTH)\n(define-data-var pox-reward-cycle-length uint REWARD_CYCLE_LENGTH)\n(define-data-var pox-rejection-fraction uint POX_REJECTION_FRACTION)\n(define-data-var first-burnchain-block-height uint u0)\n(define-data-var configured bool false)\n\n;; This function can only be called once, when it boots up\n(define-public (set-burnchain-parameters (first-burn-height uint) (prepare-cycle-length uint) (reward-cycle-length uint) (rejection-fraction uint))\n (begin\n (asserts! (not (var-get configured)) (err ERR_NOT_ALLOWED))\n (var-set first-burnchain-block-height first-burn-height)\n (var-set pox-prepare-cycle-length prepare-cycle-length)\n (var-set pox-reward-cycle-length reward-cycle-length)\n (var-set pox-rejection-fraction rejection-fraction)\n (var-set configured true)\n (ok true))\n)\n\n;; The Stacking lock-up state and associated metadata.\n;; Records can be inserted into this map via one of two ways:\n;; * via contract-call? to the (stack-stx) method, or\n;; * via a transaction in the underlying burnchain that encodes the same data.\n;; In the latter case, this map will be updated by the Stacks\n;; node itself, and transactions in the burnchain will take priority\n;; over transactions in the Stacks chain when processing this block.\n(define-map stacking-state\n { stacker: principal }\n {\n ;; how many uSTX locked?\n amount-ustx: uint,\n ;; Description of the underlying burnchain address that will\n ;; receive PoX\'ed tokens. Translating this into an address\n ;; depends on the burnchain being used. When Bitcoin is\n ;; the burnchain, this gets translated into a p2pkh, p2sh,\n ;; p2wpkh-p2sh, or p2wsh-p2sh UTXO, depending on the version.\n pox-addr: { version: (buff 1), hashbytes: (buff 20) },\n ;; how long the uSTX are locked, in reward cycles.\n lock-period: uint,\n ;; reward cycle when rewards begin\n first-reward-cycle: uint\n }\n)\n\n;; Delegation relationships\n(define-map delegation-state\n { stacker: principal }\n { \n amount-ustx: uint, ;; how many uSTX delegated?\n delegated-to: principal, ;; who are we delegating?\n until-burn-ht: (optional uint), ;; how long does the delegation last?\n ;; does the delegate _need_ to use a specific\n ;; pox recipient address?\n pox-addr: (optional { version: (buff 1), hashbytes: (buff 20) })\n }\n)\n\n;; allowed contract-callers\n(define-map allowance-contract-callers\n { sender: principal, contract-caller: principal }\n { until-burn-ht: (optional uint) })\n\n;; How many uSTX are stacked in a given reward cycle.\n;; Updated when a new PoX address is registered, or when more STX are granted\n;; to it.\n(define-map reward-cycle-total-stacked\n { reward-cycle: uint }\n { total-ustx: uint }\n)\n\n;; Internal map read by the Stacks node to iterate through the list of\n;; PoX reward addresses on a per-reward-cycle basis.\n(define-map reward-cycle-pox-address-list\n { reward-cycle: uint, index: uint }\n {\n pox-addr: { version: (buff 1), hashbytes: (buff 20) },\n total-ustx: uint\n }\n)\n\n(define-map reward-cycle-pox-address-list-len\n { reward-cycle: uint }\n { len: uint }\n)\n\n;; how much has been locked up for this address before\n;; committing?\n;; this map allows stackers to stack amounts < minimum\n;; by paying the cost of aggregation during the commit\n(define-map partial-stacked-by-cycle\n { \n pox-addr: { version: (buff 1), hashbytes: (buff 20) },\n reward-cycle: uint,\n sender: principal\n }\n { stacked-amount: uint }\n)\n\n;; Amount of uSTX that reject PoX, by reward cycle\n(define-map stacking-rejection\n { reward-cycle: uint }\n { amount: uint }\n)\n\n;; Who rejected in which reward cycle\n(define-map stacking-rejectors\n { stacker: principal, reward-cycle: uint }\n { amount: uint }\n)\n\n;; Getter for stacking-rejectors\n(define-read-only (get-pox-rejection (stacker principal) (reward-cycle uint))\n (map-get? stacking-rejectors { stacker: stacker, reward-cycle: reward-cycle }))\n\n;; Has PoX been rejected in the given reward cycle?\n(define-read-only (is-pox-active (reward-cycle uint))\n (let (\n (reject-votes \n (default-to\n u0\n (get amount (map-get? stacking-rejection { reward-cycle: reward-cycle }))))\n )\n ;; (100 * reject-votes) / stx-liquid-supply < pox-rejection-fraction \n (< (* u100 reject-votes) \n (* (var-get pox-rejection-fraction) stx-liquid-supply)))\n)\n\n;; What\'s the reward cycle number of the burnchain block height?\n;; Will runtime-abort if height is less than the first burnchain block (this is intentional)\n(define-private (burn-height-to-reward-cycle (height uint)) \n (/ (- height (var-get first-burnchain-block-height)) (var-get pox-reward-cycle-length)))\n\n;; What\'s the block height at the start of a given reward cycle?\n(define-private (reward-cycle-to-burn-height (cycle uint))\n (+ (var-get first-burnchain-block-height) (* cycle (var-get pox-reward-cycle-length))))\n\n;; What\'s the current PoX reward cycle?\n(define-private (current-pox-reward-cycle)\n (burn-height-to-reward-cycle burn-block-height))\n\n;; Get the _current_ PoX stacking principal information. If the information\n;; is expired, or if there\'s never been such a stacker, then returns none.\n(define-read-only (get-stacker-info (stacker principal))\n (match (map-get? stacking-state { stacker: stacker })\n stacking-info\n (if (<= (+ (get first-reward-cycle stacking-info) (get lock-period stacking-info)) (current-pox-reward-cycle))\n ;; present, but lock has expired\n none\n ;; present, and lock has not expired\n (some stacking-info)\n )\n ;; no state at all\n none\n ))\n\n(define-private (check-caller-allowed)\n (or (is-eq tx-sender contract-caller)\n (let ((caller-allowed \n ;; if not in the caller map, return false\n (unwrap! (map-get? allowance-contract-callers\n { sender: tx-sender, contract-caller: contract-caller })\n false)))\n ;; is the caller allowance expired?\n (if (< burn-block-height (unwrap! (get until-burn-ht caller-allowed) true))\n false\n true))))\n\n(define-private (get-check-delegation (stacker principal))\n (let ((delegation-info (try! (map-get? delegation-state { stacker: stacker }))))\n ;; did the existing delegation expire?\n (if (match (get until-burn-ht delegation-info)\n until-burn-ht (> burn-block-height until-burn-ht)\n false)\n ;; it expired, return none\n none\n ;; delegation is active\n (some delegation-info))))\n\n;; Get the size of the reward set for a reward cycle.\n;; Note that this does _not_ return duplicate PoX addresses.\n;; Note that this also _will_ return PoX addresses that are beneath\n;; the minimum threshold -- i.e. the threshold can increase after insertion.\n;; Used internally by the Stacks node, which filters out the entries\n;; in this map to select PoX addresses with enough STX.\n(define-read-only (get-reward-set-size (reward-cycle uint))\n (default-to\n u0\n (get len (map-get? reward-cycle-pox-address-list-len { reward-cycle: reward-cycle }))))\n\n;; How many rejection votes have we been accumulating for the next block\n(define-private (next-cycle-rejection-votes)\n (default-to\n u0\n (get amount (map-get? stacking-rejection { reward-cycle: (+ u1 (current-pox-reward-cycle)) }))))\n\n;; Add a single PoX address to a single reward cycle.\n;; Used to build up a set of per-reward-cycle PoX addresses.\n;; No checking will be done -- don\'t call if this PoX address is already registered in this reward cycle!\n(define-private (append-reward-cycle-pox-addr (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (reward-cycle uint)\n (amount-ustx uint))\n (let (\n (sz (get-reward-set-size reward-cycle))\n )\n (map-set reward-cycle-pox-address-list\n { reward-cycle: reward-cycle, index: sz }\n { pox-addr: pox-addr, total-ustx: amount-ustx })\n (map-set reward-cycle-pox-address-list-len\n { reward-cycle: reward-cycle }\n { len: (+ u1 sz) })\n (+ u1 sz))\n)\n\n;; How many uSTX are stacked?\n(define-read-only (get-total-ustx-stacked (reward-cycle uint))\n (default-to\n u0\n (get total-ustx (map-get? reward-cycle-total-stacked { reward-cycle: reward-cycle })))\n)\n\n;; Called internally by the node to iterate through the list of PoX addresses in this reward cycle.\n;; Returns (optional (tuple (pox-addr <pox-address>) (total-ustx <uint>)))\n(define-read-only (get-reward-set-pox-address (reward-cycle uint) (index uint))\n (map-get? reward-cycle-pox-address-list { reward-cycle: reward-cycle, index: index }))\n\n;; Add a PoX address to the ith reward cycle, if i is between 0 and the given num-cycles (exclusive).\n;; Arguments are given as a tuple, so this function can be (map ..)\'ed onto a list of its arguments.\n;; Used by add-pox-addr-to-reward-cycles.\n;; No checking is done.\n;; Returns 1 if added.\n;; Returns 0 if not added.\n(define-private (add-pox-addr-to-ith-reward-cycle (cycle-index uint) (params (tuple \n (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (first-reward-cycle uint)\n (num-cycles uint)\n (amount-ustx uint)\n (i uint))))\n (let ((reward-cycle (+ (get first-reward-cycle params) (get i params)))\n (num-cycles (get num-cycles params))\n (i (get i params)))\n {\n pox-addr: (get pox-addr params),\n first-reward-cycle: (get first-reward-cycle params),\n num-cycles: num-cycles,\n amount-ustx: (get amount-ustx params),\n i: (if (< i num-cycles)\n (let ((total-ustx (get-total-ustx-stacked reward-cycle)))\n ;; record how many uSTX this pox-addr will stack for in the given reward cycle\n (append-reward-cycle-pox-addr\n (get pox-addr params)\n reward-cycle\n (get amount-ustx params))\n\n ;; update running total\n (map-set reward-cycle-total-stacked\n { reward-cycle: reward-cycle }\n { total-ustx: (+ (get amount-ustx params) total-ustx) })\n\n ;; updated _this_ reward cycle\n (+ i u1))\n (+ i u0))\n }))\n\n;; Add a PoX address to a given sequence of reward cycle lists.\n;; A PoX address can be added to at most 12 consecutive cycles.\n;; No checking is done.\n(define-private (add-pox-addr-to-reward-cycles (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (first-reward-cycle uint)\n (num-cycles uint)\n (amount-ustx uint))\n (let ((cycle-indexes (list u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 u10 u11)))\n ;; For safety, add up the number of times (add-principal-to-ith-reward-cycle) returns 1.\n ;; It _should_ be equal to num-cycles.\n (asserts! \n (is-eq num-cycles \n (get i (fold add-pox-addr-to-ith-reward-cycle cycle-indexes \n { pox-addr: pox-addr, first-reward-cycle: first-reward-cycle, num-cycles: num-cycles, amount-ustx: amount-ustx, i: u0 })))\n (err ERR_STACKING_UNREACHABLE))\n (ok true)))\n\n(define-private (add-pox-partial-stacked-to-ith-cycle\n (cycle-index uint)\n (params { pox-addr: { version: (buff 1), hashbytes: (buff 20) },\n reward-cycle: uint,\n num-cycles: uint,\n amount-ustx: uint }))\n (let ((pox-addr (get pox-addr params))\n (num-cycles (get num-cycles params))\n (reward-cycle (get reward-cycle params))\n (amount-ustx (get amount-ustx params)))\n (let ((current-amount\n (default-to u0\n (get stacked-amount\n (map-get? partial-stacked-by-cycle { sender: tx-sender, pox-addr: pox-addr, reward-cycle: reward-cycle })))))\n (if (>= cycle-index num-cycles)\n ;; do not add to cycles >= cycle-index\n false\n ;; otherwise, add to the partial-stacked-by-cycle\n (map-set partial-stacked-by-cycle\n { sender: tx-sender, pox-addr: pox-addr, reward-cycle: reward-cycle }\n { stacked-amount: (+ amount-ustx current-amount) }))\n ;; produce the next params tuple\n { pox-addr: pox-addr,\n reward-cycle: (+ u1 reward-cycle),\n num-cycles: num-cycles,\n amount-ustx: amount-ustx })))\n\n;; Add a PoX address to a given sequence of partial reward cycle lists.\n;; A PoX address can be added to at most 12 consecutive cycles.\n;; No checking is done.\n(define-private (add-pox-partial-stacked (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (first-reward-cycle uint)\n (num-cycles uint)\n (amount-ustx uint))\n (let ((cycle-indexes (list u0 u1 u2 u3 u4 u5 u6 u7 u8 u9 u10 u11)))\n (fold add-pox-partial-stacked-to-ith-cycle cycle-indexes \n { pox-addr: pox-addr, reward-cycle: first-reward-cycle, num-cycles: num-cycles, amount-ustx: amount-ustx })\n true))\n\n;; What is the minimum number of uSTX to be stacked in the given reward cycle?\n;; Used internally by the Stacks node, and visible publicly.\n(define-read-only (get-stacking-minimum)\n (/ stx-liquid-supply STACKING_THRESHOLD_25))\n\n;; Is the address mode valid for a PoX burn address?\n(define-private (check-pox-addr-version (version (buff 1)))\n (or (is-eq version ADDRESS_VERSION_P2PKH)\n (is-eq version ADDRESS_VERSION_P2SH)\n (is-eq version ADDRESS_VERSION_P2WPKH)\n (is-eq version ADDRESS_VERSION_P2WSH)))\n\n;; Is the given lock period valid?\n(define-private (check-pox-lock-period (lock-period uint)) \n (and (>= lock-period MIN_POX_REWARD_CYCLES) \n (<= lock-period MAX_POX_REWARD_CYCLES)))\n\n;; Evaluate if a participant can stack an amount of STX for a given period.\n;; This method is designed as a read-only method so that it can be used as \n;; a set of guard conditions and also as a read-only RPC call that can be\n;; performed beforehand.\n(define-read-only (can-stack-stx (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (amount-ustx uint)\n (first-reward-cycle uint)\n (num-cycles uint))\n (begin\n ;; minimum uSTX must be met\n (asserts! (<= (print (get-stacking-minimum)) amount-ustx)\n (err ERR_STACKING_THRESHOLD_NOT_MET))\n\n (minimal-can-stack-stx pox-addr amount-ustx first-reward-cycle num-cycles)))\n\n;; Evaluate if a participant can stack an amount of STX for a given period.\n;; This method is designed as a read-only method so that it can be used as \n;; a set of guard conditions and also as a read-only RPC call that can be\n;; performed beforehand.\n(define-read-only (minimal-can-stack-stx \n (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (amount-ustx uint)\n (first-reward-cycle uint)\n (num-cycles uint))\n (begin\n ;; amount must be valid\n (asserts! (> amount-ustx u0)\n (err ERR_STACKING_INVALID_AMOUNT))\n\n ;; sender principal must not have rejected in this upcoming reward cycle\n (asserts! (is-none (get-pox-rejection tx-sender first-reward-cycle))\n (err ERR_STACKING_ALREADY_REJECTED))\n\n ;; lock period must be in acceptable range.\n (asserts! (check-pox-lock-period num-cycles)\n (err ERR_STACKING_INVALID_LOCK_PERIOD))\n\n ;; address version must be valid\n (asserts! (check-pox-addr-version (get version pox-addr))\n (err ERR_STACKING_INVALID_POX_ADDRESS))\n (ok true)))\n\n;; Revoke contract-caller authorization to call stacking methods\n(define-public (disallow-contract-caller (caller principal))\n (begin \n (asserts! (is-eq tx-sender contract-caller)\n (err ERR_STACKING_PERMISSION_DENIED))\n (ok (map-delete allowance-contract-callers { sender: tx-sender, contract-caller: caller }))))\n\n;; Give a contract-caller authorization to call stacking methods\n;; normally, stacking methods may only be invoked by _direct_ transactions\n;; (i.e., the tx-sender issues a direct contract-call to the stacking methods)\n;; by issuing an allowance, the tx-sender may call through the allowed contract\n(define-public (allow-contract-caller (caller principal) (until-burn-ht (optional uint)))\n (begin\n (asserts! (is-eq tx-sender contract-caller)\n (err ERR_STACKING_PERMISSION_DENIED))\n (ok (map-set allowance-contract-callers\n { sender: tx-sender, contract-caller: caller }\n { until-burn-ht: until-burn-ht }))))\n\n;; Lock up some uSTX for stacking! Note that the given amount here is in micro-STX (uSTX).\n;; The STX will be locked for the given number of reward cycles (lock-period).\n;; This is the self-service interface. tx-sender will be the Stacker.\n;;\n;; * The given stacker cannot currently be stacking.\n;; * You will need the minimum uSTX threshold. This will be determined by (get-stacking-minimum)\n;; at the time this method is called.\n;; * You may need to increase the amount of uSTX locked up later, since the minimum uSTX threshold\n;; may increase between reward cycles.\n;; * The Stacker will receive rewards in the reward cycle following `start-burn-ht`.\n;; Importantly, `start-burn-ht` may not be further into the future than the next reward cycle,\n;; and in most cases should be set to the current burn block height.\n;;\n;; The tokens will unlock and be returned to the Stacker (tx-sender) automatically.\n(define-public (stack-stx (amount-ustx uint)\n (pox-addr (tuple (version (buff 1)) (hashbytes (buff 20))))\n (start-burn-ht uint)\n (lock-period uint))\n ;; this stacker\'s first reward cycle is the _next_ reward cycle\n (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))\n (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht))))\n ;; the start-burn-ht must result in the next reward cycle, do not allow stackers\n ;; to \"post-date\" their `stack-stx` transaction\n (asserts! (is-eq first-reward-cycle specified-reward-cycle)\n (err ERR_INVALID_START_BURN_HEIGHT))\n\n ;; must be called directly by the tx-sender or by an allowed contract-caller\n (asserts! (check-caller-allowed)\n (err ERR_STACKING_PERMISSION_DENIED))\n\n ;; tx-sender principal must not be stacking\n (asserts! (is-none (get-stacker-info tx-sender))\n (err ERR_STACKING_ALREADY_STACKED))\n\n ;; tx-sender must not be delegating\n (asserts! (is-none (get-check-delegation tx-sender))\n (err ERR_STACKING_ALREADY_DELEGATED))\n\n ;; the Stacker must have sufficient unlocked funds\n (asserts! (>= (stx-get-balance tx-sender) amount-ustx)\n (err ERR_STACKING_INSUFFICIENT_FUNDS))\n\n ;; ensure that stacking can be performed\n (try! (can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))\n\n ;; register the PoX address with the amount stacked\n (try! (add-pox-addr-to-reward-cycles pox-addr first-reward-cycle lock-period amount-ustx))\n\n ;; add stacker record\n (map-set stacking-state\n { stacker: tx-sender }\n { amount-ustx: amount-ustx,\n pox-addr: pox-addr,\n first-reward-cycle: first-reward-cycle,\n lock-period: lock-period })\n\n ;; return the lock-up information, so the node can actually carry out the lock. \n (ok { stacker: tx-sender, lock-amount: amount-ustx, unlock-burn-height: (reward-cycle-to-burn-height (+ first-reward-cycle lock-period)) }))\n)\n\n(define-public (revoke-delegate-stx)\n (begin\n ;; must be called directly by the tx-sender or by an allowed contract-caller\n (asserts! (check-caller-allowed)\n (err ERR_STACKING_PERMISSION_DENIED))\n (ok (map-delete delegation-state { stacker: tx-sender }))))\n\n;; Delegate to `delegate-to` the ability to stack from a given address.\n;; This method _does not_ lock the funds, rather, it allows the delegate\n;; to issue the stacking lock.\n;; The caller specifies:\n;; * amount-ustx: the total amount of ustx the delegate may be allowed to lock\n;; * until-burn-ht: an optional burn height at which this delegation expiration\n;; * pox-addr: an optional address to which any rewards *must* be sent\n(define-public (delegate-stx (amount-ustx uint)\n (delegate-to principal)\n (until-burn-ht (optional uint))\n (pox-addr (optional { version: (buff 1),\n hashbytes: (buff 20) })))\n (begin\n ;; must be called directly by the tx-sender or by an allowed contract-caller\n (asserts! (check-caller-allowed)\n (err ERR_STACKING_PERMISSION_DENIED))\n\n ;; tx-sender principal must not be stacking\n (asserts! (is-none (get-stacker-info tx-sender))\n (err ERR_STACKING_ALREADY_STACKED))\n\n ;; tx-sender must not be delegating\n (asserts! (is-none (get-check-delegation tx-sender))\n (err ERR_STACKING_ALREADY_DELEGATED))\n\n ;; add delegation record\n (map-set delegation-state\n { stacker: tx-sender }\n { amount-ustx: amount-ustx,\n delegated-to: delegate-to,\n until-burn-ht: until-burn-ht,\n pox-addr: pox-addr })\n\n (ok true)))\n\n;; Commit partially stacked STX.\n;; This allows a stacker/delegate to lock fewer STX than the minimal threshold in multiple transactions,\n;; so long as: 1. The pox-addr is the same.\n;; 2. This \"commit\" transaction is called _before_ the PoX anchor block.\n;; This ensures that each entry in the reward set returned to the stacks-node is greater than the threshold,\n;; but does not require it be all locked up within a single transaction\n(define-public (stack-aggregation-commit (pox-addr { version: (buff 1), hashbytes: (buff 20) })\n (reward-cycle uint))\n (let ((partial-stacked\n ;; fetch the partial commitments\n (unwrap! (map-get? partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })\n (err ERR_STACKING_NO_SUCH_PRINCIPAL))))\n ;; must be called directly by the tx-sender or by an allowed contract-caller\n (asserts! (check-caller-allowed)\n (err ERR_STACKING_PERMISSION_DENIED))\n (let ((amount-ustx (get stacked-amount partial-stacked)))\n (try! (can-stack-stx pox-addr amount-ustx reward-cycle u1))\n ;; add the pox addr to the reward cycle\n (add-pox-addr-to-ith-reward-cycle\n u0\n { pox-addr: pox-addr,\n first-reward-cycle: reward-cycle,\n num-cycles: u1,\n amount-ustx: amount-ustx,\n i: u0 })\n ;; don\'t update the stacking-state map,\n ;; because it _already has_ this stacker\'s state\n ;; don\'t lock the STX, because the STX is already locked\n ;;\n ;; clear the partial-stacked state\n (map-delete partial-stacked-by-cycle { pox-addr: pox-addr, sender: tx-sender, reward-cycle: reward-cycle })\n (ok true))))\n\n;; As a delegate, stack the given principal\'s STX using partial-stacked-by-cycle\n;; Once the delegate has stacked > minimum, the delegate should call stack-aggregation-commit\n(define-public (delegate-stack-stx (stacker principal)\n (amount-ustx uint)\n (pox-addr { version: (buff 1), hashbytes: (buff 20) })\n (start-burn-ht uint)\n (lock-period uint))\n ;; this stacker\'s first reward cycle is the _next_ reward cycle\n (let ((first-reward-cycle (+ u1 (current-pox-reward-cycle)))\n (specified-reward-cycle (+ u1 (burn-height-to-reward-cycle start-burn-ht)))\n (unlock-burn-height (reward-cycle-to-burn-height (+ (current-pox-reward-cycle) u1 lock-period))))\n ;; the start-burn-ht must result in the next reward cycle, do not allow stackers\n ;; to \"post-date\" their `stack-stx` transaction\n (asserts! (is-eq first-reward-cycle specified-reward-cycle)\n (err ERR_INVALID_START_BURN_HEIGHT))\n\n ;; must be called directly by the tx-sender or by an allowed contract-caller\n (asserts! (check-caller-allowed)\n (err ERR_STACKING_PERMISSION_DENIED))\n\n ;; stacker must have delegated to the caller\n (let ((delegation-info (unwrap! (get-check-delegation stacker) (err ERR_STACKING_PERMISSION_DENIED))))\n ;; must have delegated to tx-sender\n (asserts! (is-eq (get delegated-to delegation-info) tx-sender)\n (err ERR_STACKING_PERMISSION_DENIED))\n ;; must have delegated enough stx\n (asserts! (>= (get amount-ustx delegation-info) amount-ustx)\n (err ERR_DELEGATION_TOO_MUCH_LOCKED))\n ;; if pox-addr is set, must be equal to pox-addr\n (asserts! (match (get pox-addr delegation-info)\n specified-pox-addr (is-eq pox-addr specified-pox-addr)\n true)\n (err ERR_DELEGATION_POX_ADDR_REQUIRED))\n ;; delegation must not expire before lock period\n (asserts! (match (get until-burn-ht delegation-info)\n until-burn-ht (>= until-burn-ht\n unlock-burn-height)\n true)\n (err ERR_DELEGATION_EXPIRES_DURING_LOCK)))\n\n ;; stacker principal must not be stacking\n (asserts! (is-none (get-stacker-info stacker))\n (err ERR_STACKING_ALREADY_STACKED))\n\n ;; the Stacker must have sufficient unlocked funds\n (asserts! (>= (stx-get-balance stacker) amount-ustx)\n (err ERR_STACKING_INSUFFICIENT_FUNDS))\n\n ;; ensure that stacking can be performed\n (try! (minimal-can-stack-stx pox-addr amount-ustx first-reward-cycle lock-period))\n\n ;; register the PoX address with the amount stacked via partial stacking\n ;; before it can be included in the reward set, this must be committed!\n (add-pox-partial-stacked pox-addr first-reward-cycle lock-period amount-ustx)\n\n ;; add stacker record\n (map-set stacking-state\n { stacker: stacker }\n { amount-ustx: amount-ustx,\n pox-addr: pox-addr,\n first-reward-cycle: first-reward-cycle,\n lock-period: lock-period })\n\n ;; return the lock-up information, so the node can actually carry out the lock. \n (ok { stacker: stacker,\n lock-amount: amount-ustx,\n unlock-burn-height: unlock-burn-height })))\n\n;; Reject Stacking for this reward cycle.\n;; tx-sender votes all its uSTX for rejection.\n;; Note that unlike PoX, rejecting PoX does not lock the tx-sender\'s\n;; tokens. PoX rejection acts like a coin vote.\n(define-public (reject-pox)\n (let (\n (balance (stx-get-balance tx-sender))\n (vote-reward-cycle (+ u1 (current-pox-reward-cycle)))\n )\n\n ;; tx-sender principal must not have rejected in this upcoming reward cycle\n (asserts! (is-none (get-pox-rejection tx-sender vote-reward-cycle))\n (err ERR_STACKING_ALREADY_REJECTED))\n\n ;; tx-sender can\'t be a stacker\n (asserts! (is-none (get-stacker-info tx-sender))\n (err ERR_STACKING_ALREADY_STACKED))\n\n ;; vote for rejection\n (map-set stacking-rejection\n { reward-cycle: vote-reward-cycle }\n { amount: (+ (next-cycle-rejection-votes) balance) }\n )\n\n ;; mark voted\n (map-set stacking-rejectors\n { stacker: tx-sender, reward-cycle: vote-reward-cycle }\n { amount: balance }\n )\n\n (ok true))\n)\n\n;; Used for PoX parameters discovery\n(define-read-only (get-pox-info)\n (ok {\n min-amount-ustx: (get-stacking-minimum),\n reward-cycle-id: (current-pox-reward-cycle),\n prepare-cycle-length: (var-get pox-prepare-cycle-length),\n first-burnchain-block-height: (var-get first-burnchain-block-height),\n reward-cycle-length: (var-get pox-reward-cycle-length),\n rejection-fraction: (var-get pox-rejection-fraction),\n current-rejection-votes: (next-cycle-rejection-votes),\n total-liquid-supply-ustx: stx-liquid-supply,\n })\n)\n";