WIP: PoX-5 and Epoch 4#7197
Conversation
* pipe through the outputs from burndb to sortdb * add validation routine for the L1 locking scripts * add validation for the PoX reward set, checking scripts for matching outputs
Also includes the linked list and other state for per-cycle signer set state.
Also moved the computation logic to a separate helper function, to help with unit testing.
The expected p2wsh script will instead now be computed in Clarity and then the new function to be added will verify that the output exists.
Also simplifies many matches to reduce the number of places that need to be touched each time an epoch or clarity version is added.
Merge feat/p2wsh validation
| ;; this is a list of outputs corresponding to their timelocks. | ||
| ;; If the response is `err`, this is the amount of sBTC (in sats) | ||
| ;; that they want to lock. | ||
| (btc-lockup (response { |
There was a problem hiding this comment.
I think this being a response is bad for UX. I'd rather see two optionals, btc-lockup and sbtc-lockup, with a check to ensure they are not both set.
| is-bond: bool, | ||
| index: uint, |
There was a problem hiding this comment.
It would be nice if the ordering of these keys is consistent across all of these maps, I think is-bond is first, then index is second makes the most sense.
| (ok { | ||
| unlock-burn-height: (reward-cycle-to-unlock-height unlock-cycle), | ||
| staker: tx-sender, | ||
| signer: signer, | ||
| prev-unlock-height: prev-unlock-cycle, | ||
| unlock-cycle: unlock-cycle, | ||
| num-cycles: num-cycles, | ||
| amount-ustx: new-lock-amount, | ||
| }) |
There was a problem hiding this comment.
Again, field ordering in tuples is nice to be consistent when possible.
(ok {
- unlock-burn-height: (reward-cycle-to-unlock-height unlock-cycle),
- staker: tx-sender,
signer: signer,
+ staker: tx-sender,
+ amount-ustx: new-lock-amount,
+ num-cycles: num-cycles,
prev-unlock-height: prev-unlock-cycle,
+ unlock-burn-height: (reward-cycle-to-unlock-height unlock-cycle),
unlock-cycle: unlock-cycle,
- num-cycles: num-cycles,
- amount-ustx: new-lock-amount,
})
)
)| ) | ||
| ) | ||
|
|
||
| (define-public (calculate-rewards (bond-periods (list 6 uint))) |
There was a problem hiding this comment.
It might be nice to have a read-only version of this that could be called any time to estimate rewards, and then call that from the actual one that checks the proper height and sets the persistent storage.
* Push PoX-5 activation far ahead in the snap/consensus tests: those are not ready for PoX-5 activation, and will require integration once signer-set calculation is in place. This is the bulk of the changeset (all the snap files are touched because this impacts the pox-4 auto-unlock heights) * Remove the force-activate test instruction for PoX-5 calculation * Compute the first-waterfall reward set with `PoxConstants` PoX-5 activation rather than Epoch-4.0 height * Fix the signer set fetch API so that it will return a pox-5 signer set
| ;; Keep these constants in lock-step with the address version buffs above | ||
| ;; Maximum value of an address version as a uint | ||
| (define-constant MAX_ADDRESS_VERSION u6) | ||
| ;; Maximum value of an address version that has a 20-byte hashbytes | ||
| ;; (0x00, 0x01, 0x02, 0x03, and 0x04 have 20-byte hashbytes) | ||
| (define-constant MAX_ADDRESS_VERSION_BUFF_20 u4) | ||
| ;; Maximum value of an address version that has a 32-byte hashbytes | ||
| ;; (0x05 and 0x06 have 32-byte hashbytes) | ||
| (define-constant MAX_ADDRESS_VERSION_BUFF_32 u6) |
There was a problem hiding this comment.
These are unused and can be deleted.
|
|
||
| ;; Used to prevent fractional multiplication errors | ||
| ;; during reward calculations | ||
| (define-constant PRECISION u1000000000000000000) ;; 1e18 |
There was a problem hiding this comment.
It will be better performance for this to be a power of 2 (multiplies and divides become shifts).
| ;; The signer must have been registered already | ||
| (asserts! (is-some (get-signer-info signer)) ERR_SIGNER_NOT_FOUND) | ||
|
|
||
| ;; the start-burn-ht must result in the next reward cycle, do not allow stackers |
There was a problem hiding this comment.
| ;; the start-burn-ht must result in the next reward cycle, do not allow stackers | |
| ;; the start-burn-ht must result in the next reward cycle, do not allow stakers |
| ;;;; tx-sender principal must not be in a bond membership | ||
| (asserts! (is-none (get-bond-membership tx-sender)) ERR_ALREADY_STAKED) | ||
|
|
||
| ;;;; the Stacker must have sufficient unlocked funds |
There was a problem hiding this comment.
| ;;;; the Stacker must have sufficient unlocked funds | |
| ;;;; the staker must have sufficient unlocked funds |
Also, what's with the ;;;; for some comments?
| )) | ||
| ) | ||
|
|
||
| ;; Revoke contract-caller authorization to call stacking methods |
There was a problem hiding this comment.
| ;; Revoke contract-caller authorization to call stacking methods | |
| ;; Revoke contract-caller authorization to call staking methods |
PoX-5: Integrate sbtc address calculation
| ;; normally, stacking methods may only be invoked by _direct_ transactions | ||
| ;; (i.e., the tx-sender issues a direct contract-call to the stacking methods) | ||
| ;; by issuing an allowance, the tx-sender may call through the allowed contract | ||
| (define-public (allow-contract-caller |
There was a problem hiding this comment.
Are we still going to consider the post-condition replacement for this? I think it would be nice. See discussion.
| ;; Give a contract-caller authorization to call stacking methods | ||
| ;; normally, stacking methods may only be invoked by _direct_ transactions | ||
| ;; (i.e., the tx-sender issues a direct contract-call to the stacking methods) |
There was a problem hiding this comment.
"stacking" -> "staking" x 3
| ) | ||
|
|
||
| (match last-item | ||
| last-stacker (let ((last-node (unwrap-panic (map-get? staker-set-ll-for-cycle { |
| ) | ||
|
|
||
| (define-private (remove-staker-from-set-for-cycle | ||
| (stacker principal) |
| (next-item (get next node)) | ||
| ) | ||
| (match prev-item | ||
| prev-stacker |
| ;; State for tracking used signer key authorizations. This prevents re-use | ||
| ;; of the same signature or pre-set authorization for multiple transactions. | ||
| ;; Refer to the `signer-key-authorizations` map for the documentation on these fields | ||
| (define-map used-signer-key-authorizations | ||
| { | ||
| signer-key: (buff 33), | ||
| reward-cycle: uint, | ||
| period: uint, | ||
| topic: (string-ascii 14), | ||
| pox-addr: (optional { | ||
| version: (buff 1), | ||
| hashbytes: (buff 32), | ||
| }), | ||
| auth-id: uint, | ||
| max-amount: uint, | ||
| } | ||
| bool ;; Whether the field has been used or not | ||
| ) |
There was a problem hiding this comment.
We don't need this any more.
| index: uint, | ||
| is-bond: bool, | ||
| staker: principal, | ||
| signer: principal, |
There was a problem hiding this comment.
Is it necessary to include the signer in the key here? I think we're already guaranteed to only have one entry per index/is-bond/staker, and adding the signer is just complicating it.
| index: cycle, | ||
| signer: signer, | ||
| is-bond: false, |
There was a problem hiding this comment.
Let's keep the ordering consistent.
| ;; This is strictly for reward calculations - ie the STX | ||
| ;; from Bitcoin staking are not accounted for here. |
There was a problem hiding this comment.
This comment could be more clear. Maybe something like:
This is strictly for reward calculations - i.e. when is-bond is false, only the STX from STX-only staking is accounted for here, not the STX from bonds.
| ;;;; The last accounted balance (of sBTC held by this contract) | ||
| ;;;; at a time of reward computation. | ||
| ;;;; N.B. it is critical that this value is set to the contract's | ||
| ;;;; sBTC balance after any transfer of sBTC out of this contract. | ||
| ;; (define-data-var last-accounted-balance uint u0) |
There was a problem hiding this comment.
I think this is just going to be another place for an error to crop up. Let's not track this, and just use sBTC's functions to figure out how much the contract holds.
| (available-rewards (get available-rewards accumulator)) | ||
| ;; How much sBTC the bond is supposed to earn per calculation, | ||
| ;; which is (totalSats * apy) / 48 | ||
| (target-yield (/ (/ (* total-sats (get target-rate bond)) u10000) u48)) |
There was a problem hiding this comment.
If the target rate is an APY, and we are calculating the target yield for 1 pay cycle, I think we should be dividing by 50, not 48.
X = year / pay cycles
1 pay cycle = 1050 blocks
1 year = 365.25 days * 24 hours/day * 60 min/day = 525,960 min
1 block = 10 min
1 year = 52,596 blocks
X = 52,596 blocks / 1050 blocks ~= 50
There was a problem hiding this comment.
Or are we just assuming that two consecutive bonds is approximately 1 year, so there are ~48 pay periods in one year.
| (define-constant ERR_CANNOT_SETUP_BOND_TOO_LATE (err u3)) | ||
| (define-constant ERR_BOND_ALREADY_SETUP (err u4)) | ||
| (define-constant ERR_STAKER_ALREADY_ADDED (err u5)) | ||
| (define-constant ERR_L1_LOCKUP_NOT_FOUND (err u6)) |
There was a problem hiding this comment.
Several of these constants are never used.
This is an in-progress PR for iterative development of pox-5 work