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";