Merge pull request #18 from alexgo-io/feat/lqstx-mint-endpoint-v1-01

lqstx-mint-endpoint-v1-01
This commit is contained in:
fiftyeightandeight
2024-03-12 18:02:57 +08:00
committed by GitHub
13 changed files with 421 additions and 112 deletions

View File

@@ -8,6 +8,7 @@ cache_dir = "./.cache"
[[project.requirements]]
contract_id = "SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2"
[[project.requirements]]
contract_id = "SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2"
@@ -155,6 +156,10 @@ path = "contracts/traits/sip-010-trait.clar"
epoch = 2.4
[contracts.rebase-strategy-trait]
path = "contracts/deployed/rebase-strategy-trait.clar"
epoch = 2.4
[contracts.rebase-strategy-trait-v1-01]
path = "contracts/traits/rebase-strategy-trait.clar"
epoch = 2.4
@@ -170,10 +175,14 @@ epoch = 2.4
path = "contracts/extensions/public-pools-strategy-manager.clar"
epoch = 2.4
[contracts.lqstx-mint-endpoint]
[contracts.lqstx-mint-endpoint-v1-01]
path = "contracts/extensions/lqstx-mint-endpoint.clar"
epoch = 2.4
[contracts.lqstx-mint-endpoint]
path = "contracts/deployed/lqstx-mint-endpoint.clar"
epoch = 2.4
[contracts.lqstx-mint-registry]
path = "contracts/aux/lqstx-mint-registry.clar"
epoch = 2.4

View File

@@ -3,7 +3,8 @@
(define-public (execute (sender principal))
(begin
(try! (contract-call? .lisa-dao set-extensions (list
{ extension: .lqstx-mint-endpoint, enabled: true }
{ extension: .lqstx-mint-endpoint, enabled: false }
{ extension: .lqstx-mint-endpoint-v1-01, enabled: true }
{ extension: .lqstx-vault, enabled: true }
{ extension: .treasury, enabled: true }
{ extension: .token-vesting, enabled: true }
@@ -28,6 +29,7 @@
(try! (contract-call? .operators set-proposal-threshold 4))
;; Set initial strategy managers, sender is the deployer
;; TODO add manager
(try! (contract-call? .public-pools-strategy-manager set-authorised-manager sender true))
;; Mint max LISA token supply (1bn)
@@ -36,8 +38,8 @@
)))
;; Enable whitelist
(try! (contract-call? .lqstx-mint-endpoint set-use-whitelist true))
(try! (contract-call? .lqstx-mint-endpoint set-whitelisted-many
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-use-whitelist true))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-whitelisted-many
(list
'SP3BQ65DRM8DMTYDD5HWMN60EYC0JFS5NC2V5CWW7
'SP2VZBR9GCVM33BN0WXA05VJP6QV7CJ3Z3SQKJ5HH
@@ -52,7 +54,7 @@
true
true
)))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-paused false))
(ok true)
)
)

View File

@@ -0,0 +1,237 @@
;;
;; lqstx-mint-endpoint
;;
(use-trait sip-010-trait .sip-010-trait.sip-010-trait)
(use-trait rebase-strategy-trait .rebase-strategy-trait.rebase-strategy-trait)
(define-constant err-unauthorised (err u1000))
(define-constant err-paused (err u1001))
(define-constant err-request-pending (err u1006))
(define-constant err-request-finalized-or-revoked (err u1007))
(define-constant err-not-whitelisted (err u1008))
(define-constant PENDING 0x00)
(define-constant FINALIZED 0x01)
(define-constant REVOKED 0x02)
(define-constant max-uint u340282366920938463463374607431768211455)
(define-data-var paused bool true)
(define-data-var mint-delay uint u144) ;; mint available 1 day after cycle starts
;; @dev used for testing only
(define-data-var activation-block uint u0)
(define-data-var reward-cycle-length uint u2016) ;; 2 weeks
(define-data-var use-whitelist bool false)
(define-map whitelisted principal bool)
;; read-only calls
(define-read-only (is-dao-or-extension)
(ok (asserts! (or (is-eq tx-sender .lisa-dao) (contract-call? .lisa-dao is-extension contract-caller)) err-unauthorised)))
(define-read-only (is-paused)
(var-get paused))
(define-read-only (is-paused-or-fail)
(ok (asserts! (not (is-paused)) err-paused)))
(define-read-only (get-mint-request-or-fail (request-id uint))
(contract-call? .lqstx-mint-registry get-mint-request-or-fail request-id))
(define-read-only (get-burn-request-or-fail (request-id uint))
(contract-call? .lqstx-mint-registry get-burn-request-or-fail request-id))
(define-read-only (get-mint-requests-pending-or-default (user principal))
(contract-call? .lqstx-mint-registry get-mint-requests-pending-or-default user))
(define-read-only (get-burn-requests-pending-or-default (user principal))
(contract-call? .lqstx-mint-registry get-burn-requests-pending-or-default user))
(define-read-only (get-mint-requests-pending-amount)
(contract-call? .lqstx-mint-registry get-mint-requests-pending-amount))
(define-read-only (get-mint-request-or-fail-many (request-ids (list 1000 uint)))
(ok (map get-mint-request-or-fail request-ids)))
(define-read-only (get-burn-request-or-fail-many (request-ids (list 1000 uint)))
(ok (map get-burn-request-or-fail request-ids)))
(define-read-only (validate-mint-request (request-id uint))
(let (
(request-details (try! (contract-call? .lqstx-mint-registry get-mint-request-or-fail request-id)))
(request-id-idx (unwrap! (index-of? (get-mint-requests-pending-or-default (get requested-by request-details)) request-id) err-request-finalized-or-revoked)))
(asserts! (>= block-height (+ (get-first-stacks-block-in-reward-cycle (+ (get requested-at request-details) u1)) (var-get mint-delay))) err-request-pending)
(ok request-id-idx)))
;; @dev it favours smaller amounts as we do not allow partial burn
(define-read-only (validate-burn-request (request-id uint))
(let (
(request-details (try! (contract-call? .lqstx-mint-registry get-burn-request-or-fail request-id)))
(request-id-idx (unwrap! (index-of? (get-burn-requests-pending-or-default (get requested-by request-details)) request-id) err-request-finalized-or-revoked))
(vaulted-amount (contract-call? .token-vlqstx get-shares-to-tokens (get wrapped-amount request-details))))
(asserts! (>= (stx-get-balance .lqstx-vault) vaulted-amount) err-request-pending)
(ok { vaulted-amount: vaulted-amount, request-id-idx: request-id-idx })))
;; @dev used for testing only
(define-read-only (get-reward-cycle (stacks-height uint))
;; (some (contract-call? 'SP000000000000000000002Q6VF78.pox-3 current-pox-reward-cycle)))
(if (>= stacks-height (var-get activation-block))
(some (/ (- stacks-height (var-get activation-block)) (var-get reward-cycle-length)))
none))
;; @dev used for testing only
(define-read-only (get-first-stacks-block-in-reward-cycle (reward-cycle uint))
;; (contract-call? 'SP000000000000000000002Q6VF78.pox-3 reward-cycle-to-burn-height reward-cycle))
(+ (var-get activation-block) (* (var-get reward-cycle-length) reward-cycle)))
(define-read-only (get-mint-delay)
(var-get mint-delay))
(define-read-only (is-whitelisted-or-mint-for-all (user principal))
(or (not (var-get use-whitelist)) (default-to false (map-get? whitelisted user))))
;; governance calls
(define-public (set-use-whitelist (new-use bool))
(begin
(try! (is-dao-or-extension))
(ok (var-set use-whitelist new-use))))
(define-public (set-whitelisted (user principal) (new-whitelisted bool))
(begin
(try! (is-dao-or-extension))
(set-whitelisted-private user new-whitelisted)))
(define-public (set-whitelisted-many (users (list 1000 principal)) (new-whitelisteds (list 1000 bool)))
(begin
(try! (is-dao-or-extension))
(fold check-err (map set-whitelisted-private users new-whitelisteds) (ok true))))
(define-public (set-paused (new-paused bool))
(begin
(try! (is-dao-or-extension))
(ok (var-set paused new-paused))))
(define-public (set-mint-delay (new-delay uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set mint-delay new-delay))))
;; @dev used for testing only
(define-public (set-reward-cycle-length (new-reward-cycle-length uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set reward-cycle-length new-reward-cycle-length))))
;; public calls
;; @dev the requestor stx is held by the contract until mint can be finalized.
(define-public (request-mint (amount uint))
(let (
(sender tx-sender)
(cycle (unwrap-panic (get-reward-cycle block-height)))
(request-details { requested-by: sender, amount: amount, requested-at: cycle, status: PENDING })
(request-id (try! (contract-call? .lqstx-mint-registry set-mint-request u0 request-details))))
(try! (is-paused-or-fail))
(asserts! (is-whitelisted-or-mint-for-all sender) err-not-whitelisted)
(try! (stx-transfer? amount sender .lqstx-vault))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (+ (get-mint-requests-pending-amount) amount)))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending sender (unwrap-panic (as-max-len? (append (get-mint-requests-pending-or-default sender) request-id) u1000))))
(print { type: "mint-request", id: request-id, details: request-details })
(ok request-id)))
(define-public (finalize-mint (request-id uint))
(let (
(request-details (try! (get-mint-request-or-fail request-id)))
(mint-requests (get-mint-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (try! (validate-mint-request request-id))))
(try! (is-paused-or-fail))
(try! (is-dao-or-extension))
(try! (contract-call? .token-lqstx dao-mint (get amount request-details) (get requested-by request-details)))
(try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: FINALIZED })))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending (get requested-by request-details) (pop mint-requests request-id-idx)))
(ok true)))
(define-public (finalize-mint-many (request-ids (list 1000 uint)))
(fold check-err (map finalize-mint request-ids) (ok true)))
(define-public (revoke-mint (request-id uint))
(let (
(request-details (try! (get-mint-request-or-fail request-id)))
(mint-requests (get-mint-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? mint-requests request-id) err-request-finalized-or-revoked)))
(try! (is-paused-or-fail))
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get amount request-details), recipient: (get requested-by request-details) }))))
(try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending (get requested-by request-details) (pop mint-requests request-id-idx)))
(ok true)))
(define-public (request-burn (amount uint) (rebase-trait <rebase-strategy-trait>))
(let (
(sender tx-sender)
;; @dev requested-at not used for burn
(cycle (unwrap-panic (get-reward-cycle block-height)))
(vlqstx-amount (contract-call? .token-vlqstx get-tokens-to-shares amount))
(request-details { requested-by: sender, amount: amount, wrapped-amount: vlqstx-amount, requested-at: cycle, status: PENDING })
(request-id (try! (contract-call? .lqstx-mint-registry set-burn-request u0 request-details))))
(try! (is-paused-or-fail))
(try! (contract-call? .token-vlqstx mint amount sender))
(try! (contract-call? .token-vlqstx transfer vlqstx-amount sender .lqstx-mint-registry none))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending sender (unwrap-panic (as-max-len? (append (get-burn-requests-pending-or-default sender) request-id) u1000))))
(match (contract-call? rebase-trait finalize-burn request-id)
ok-value (ok { request-id: request-id, status: FINALIZED })
err-value (begin (print { type: "burn-request", id: request-id, details: request-details, finalize-err: err-value }) (ok { request-id: request-id, status: PENDING })))))
(define-public (finalize-burn (request-id uint))
(let (
(request-details (try! (get-burn-request-or-fail request-id)))
(transfer-vlqstx (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx)))
(burn-requests (get-burn-requests-pending-or-default (get requested-by request-details)))
(validation-data (try! (validate-burn-request request-id))))
(try! (is-paused-or-fail))
(try! (is-dao-or-extension))
(try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) (as-contract tx-sender)))
(try! (contract-call? .token-lqstx dao-burn (get vaulted-amount validation-data) (as-contract tx-sender)))
(try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get vaulted-amount validation-data), recipient: (get requested-by request-details) }))))
(try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED })))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending (get requested-by request-details) (pop burn-requests (get request-id-idx validation-data))))
(ok true)))
(define-public (finalize-burn-many (request-ids (list 1000 uint)))
(fold check-err (map finalize-burn request-ids) (ok true)))
(define-public (revoke-burn (request-id uint))
(let (
(request-details (try! (get-burn-request-or-fail request-id)))
(burn-requests (get-burn-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? burn-requests request-id) err-request-finalized-or-revoked))
(lqstx-amount (contract-call? .token-vlqstx get-shares-to-tokens (get wrapped-amount request-details))))
(try! (is-paused-or-fail))
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx))
(try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) (as-contract tx-sender)))
(try! (contract-call? .token-lqstx transfer lqstx-amount (as-contract tx-sender) (get requested-by request-details) none))
(try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending (get requested-by request-details) (pop burn-requests request-id-idx)))
(ok true)))
(define-private (check-err (result (response bool uint)) (prior (response bool uint)))
(match prior
ok-value result
err-value (err err-value)))
(define-private (pop (target (list 1000 uint)) (idx uint))
(match (slice? target (+ idx u1) (len target))
some-value (unwrap-panic (as-max-len? (concat (unwrap-panic (slice? target u0 idx)) some-value) u1000))
(unwrap-panic (slice? target u0 idx))))
(define-private (set-whitelisted-private (user principal) (new-whitelisted bool))
(ok (map-set whitelisted user new-whitelisted)))

View File

@@ -0,0 +1,8 @@
(define-trait rebase-strategy-trait
(
(rebase () (response uint uint))
(finalize-mint (uint) (response bool uint))
(finalize-burn (uint) (response bool uint))
)
)

View File

@@ -11,7 +11,7 @@
)
(define-public (rebase (strategies (list 20 <strategy-trait>)))
(let ((total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts strategies (ok u0)))) (contract-call? .lqstx-mint-endpoint get-mint-requests-pending-amount))))
(let ((total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts strategies (ok u0)))) (contract-call? .lqstx-mint-endpoint-v1-01 get-mint-requests-pending-amount))))
(try! (is-dao-or-extension))
(as-contract (try! (contract-call? .token-lqstx set-reserve total-stx)))
(ok total-stx)

View File

@@ -1,8 +1,7 @@
;;
;; lqstx-mint-endpoint
;; lqstx-mint-endpoint-v1-01
;;
(use-trait sip-010-trait .sip-010-trait.sip-010-trait)
(use-trait rebase-strategy-trait .rebase-strategy-trait.rebase-strategy-trait)
(define-constant err-unauthorised (err u1000))
(define-constant err-paused (err u1001))
@@ -17,11 +16,11 @@
(define-constant max-uint u340282366920938463463374607431768211455)
(define-data-var paused bool true)
(define-data-var mint-delay uint u144) ;; mint available 1 day after cycle starts
(define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts
;; @dev used for testing only
(define-data-var activation-block uint u0)
(define-data-var reward-cycle-length uint u2016) ;; 2 weeks
;; corresponds to `first-burnchain-block-height` and `pox-reward-cycle-length` in pox-3
(define-data-var activation-burn-block uint u666050)
(define-data-var reward-cycle-length uint u2100)
(define-data-var use-whitelist bool false)
(define-map whitelisted principal bool)
@@ -62,7 +61,7 @@
(let (
(request-details (try! (contract-call? .lqstx-mint-registry get-mint-request-or-fail request-id)))
(request-id-idx (unwrap! (index-of? (get-mint-requests-pending-or-default (get requested-by request-details)) request-id) err-request-finalized-or-revoked)))
(asserts! (>= block-height (+ (get-first-stacks-block-in-reward-cycle (+ (get requested-at request-details) u1)) (var-get mint-delay))) err-request-pending)
(asserts! (>= burn-block-height (+ (get-first-burn-block-in-reward-cycle (+ (get requested-at request-details) u1)) (var-get mint-delay))) err-request-pending)
(ok request-id-idx)))
;; @dev it favours smaller amounts as we do not allow partial burn
@@ -74,17 +73,13 @@
(asserts! (>= (stx-get-balance .lqstx-vault) vaulted-amount) err-request-pending)
(ok { vaulted-amount: vaulted-amount, request-id-idx: request-id-idx })))
;; @dev used for testing only
(define-read-only (get-reward-cycle (stacks-height uint))
(some (contract-call? 'SP000000000000000000002Q6VF78.pox-3 current-pox-reward-cycle)))
;; (if (>= stacks-height (var-get activation-block))
;; (some (/ (- stacks-height (var-get activation-block)) (var-get reward-cycle-length)))
;; none))
(define-read-only (get-reward-cycle (burn-block uint))
(if (>= burn-block (var-get activation-burn-block))
(some (/ (- burn-block (var-get activation-burn-block)) (var-get reward-cycle-length)))
none))
;; @dev used for testing only
(define-read-only (get-first-stacks-block-in-reward-cycle (reward-cycle uint))
(contract-call? 'SP000000000000000000002Q6VF78.pox-3 reward-cycle-to-burn-height reward-cycle))
;; (+ (var-get activation-block) (* (var-get reward-cycle-length) reward-cycle)))
(define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint))
(+ (var-get activation-burn-block) (* (var-get reward-cycle-length) reward-cycle)))
(define-read-only (get-mint-delay)
(var-get mint-delay))
@@ -92,15 +87,62 @@
(define-read-only (is-whitelisted-or-mint-for-all (user principal))
(or (not (var-get use-whitelist)) (default-to false (map-get? whitelisted user))))
;; public calls
;; @dev the requestor stx is held by the contract until mint can be finalized.
(define-public (request-mint (amount uint))
(let (
(sender tx-sender)
(cycle (unwrap-panic (get-reward-cycle burn-block-height)))
(request-details { requested-by: sender, amount: amount, requested-at: cycle, status: PENDING })
(request-id (try! (contract-call? .lqstx-mint-registry set-mint-request u0 request-details))))
(try! (is-paused-or-fail))
(asserts! (is-whitelisted-or-mint-for-all sender) err-not-whitelisted)
(try! (stx-transfer? amount sender .lqstx-vault))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (+ (get-mint-requests-pending-amount) amount)))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending sender (unwrap-panic (as-max-len? (append (get-mint-requests-pending-or-default sender) request-id) u1000))))
(print { type: "mint-request", id: request-id, details: request-details })
(ok request-id)))
(define-public (revoke-mint (request-id uint))
(let (
(request-details (try! (get-mint-request-or-fail request-id)))
(mint-requests (get-mint-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? mint-requests request-id) err-request-finalized-or-revoked)))
(try! (is-paused-or-fail))
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get amount request-details), recipient: (get requested-by request-details) }))))
(try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending (get requested-by request-details) (pop mint-requests request-id-idx)))
(ok true)))
(define-public (revoke-burn (request-id uint))
(let (
(request-details (try! (get-burn-request-or-fail request-id)))
(burn-requests (get-burn-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? burn-requests request-id) err-request-finalized-or-revoked))
(lqstx-amount (contract-call? .token-vlqstx get-shares-to-tokens (get wrapped-amount request-details))))
(try! (is-paused-or-fail))
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx))
(try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) (as-contract tx-sender)))
(try! (contract-call? .token-lqstx transfer lqstx-amount (as-contract tx-sender) (get requested-by request-details) none))
(try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending (get requested-by request-details) (pop burn-requests request-id-idx)))
(ok true)))
;; governance calls
(define-public (set-use-whitelist (new-use bool))
(begin
(begin
(try! (is-dao-or-extension))
(ok (var-set use-whitelist new-use))))
(define-public (set-whitelisted (user principal) (new-whitelisted bool))
(begin
(begin
(try! (is-dao-or-extension))
(set-whitelisted-private user new-whitelisted)))
@@ -119,28 +161,17 @@
(try! (is-dao-or-extension))
(ok (var-set mint-delay new-delay))))
;; @dev used for testing only
(define-public (set-activation-burn-block (new-activation-burn-block uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set activation-burn-block new-activation-burn-block))))
(define-public (set-reward-cycle-length (new-reward-cycle-length uint))
(begin
(try! (is-dao-or-extension))
(ok (var-set reward-cycle-length new-reward-cycle-length))))
;; public calls
;; @dev the requestor stx is held by the contract until mint can be finalized.
(define-public (request-mint (amount uint))
(let (
(sender tx-sender)
(cycle (unwrap-panic (get-reward-cycle block-height)))
(request-details { requested-by: sender, amount: amount, requested-at: cycle, status: PENDING })
(request-id (try! (contract-call? .lqstx-mint-registry set-mint-request u0 request-details))))
(try! (is-paused-or-fail))
(asserts! (is-whitelisted-or-mint-for-all sender) err-not-whitelisted)
(try! (stx-transfer? amount sender .lqstx-vault))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (+ (get-mint-requests-pending-amount) amount)))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending sender (unwrap-panic (as-max-len? (append (get-mint-requests-pending-or-default sender) request-id) u1000))))
(print { type: "mint-request", id: request-id, details: request-details })
(ok request-id)))
;; privileged calls
(define-public (finalize-mint (request-id uint))
(let (
@@ -158,35 +189,20 @@
(define-public (finalize-mint-many (request-ids (list 1000 uint)))
(fold check-err (map finalize-mint request-ids) (ok true)))
(define-public (revoke-mint (request-id uint))
(define-public (request-burn (sender principal) (amount uint))
(let (
(request-details (try! (get-mint-request-or-fail request-id)))
(mint-requests (get-mint-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? mint-requests request-id) err-request-finalized-or-revoked)))
(try! (is-paused-or-fail))
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get amount request-details), recipient: (get requested-by request-details) }))))
(try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))
(try! (contract-call? .lqstx-mint-registry set-mint-requests-pending (get requested-by request-details) (pop mint-requests request-id-idx)))
(ok true)))
(define-public (request-burn (amount uint) (rebase-trait <rebase-strategy-trait>))
(let (
(sender tx-sender)
;; @dev requested-at not used for burn
(cycle (unwrap-panic (get-reward-cycle block-height)))
(cycle (unwrap-panic (get-reward-cycle burn-block-height)))
(vlqstx-amount (contract-call? .token-vlqstx get-tokens-to-shares amount))
(request-details { requested-by: sender, amount: amount, wrapped-amount: vlqstx-amount, requested-at: cycle, status: PENDING })
(request-id (try! (contract-call? .lqstx-mint-registry set-burn-request u0 request-details))))
(try! (is-paused-or-fail))
(try! (contract-call? .token-vlqstx mint amount sender))
(try! (contract-call? .token-vlqstx transfer vlqstx-amount sender .lqstx-mint-registry none))
(try! (is-dao-or-extension))
(try! (contract-call? .token-vlqstx mint amount tx-sender))
(try! (contract-call? .token-vlqstx transfer vlqstx-amount tx-sender .lqstx-mint-registry none))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending sender (unwrap-panic (as-max-len? (append (get-burn-requests-pending-or-default sender) request-id) u1000))))
(match (contract-call? rebase-trait finalize-burn request-id)
ok-value (ok { request-id: request-id, status: FINALIZED })
err-value (begin (print { type: "burn-request", id: request-id, details: request-details, finalize-err: err-value }) (ok { request-id: request-id, status: PENDING })))))
(print { type: "burn-request", id: request-id, details: request-details })
(ok { request-id: request-id, status: PENDING })))
(define-public (finalize-burn (request-id uint))
(let (
@@ -194,7 +210,7 @@
(transfer-vlqstx (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx)))
(burn-requests (get-burn-requests-pending-or-default (get requested-by request-details)))
(validation-data (try! (validate-burn-request request-id))))
(try! (is-paused-or-fail))
(try! (is-paused-or-fail))
(try! (is-dao-or-extension))
(try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) (as-contract tx-sender)))
(try! (contract-call? .token-lqstx dao-burn (get vaulted-amount validation-data) (as-contract tx-sender)))
@@ -206,21 +222,7 @@
(define-public (finalize-burn-many (request-ids (list 1000 uint)))
(fold check-err (map finalize-burn request-ids) (ok true)))
(define-public (revoke-burn (request-id uint))
(let (
(request-details (try! (get-burn-request-or-fail request-id)))
(burn-requests (get-burn-requests-pending-or-default (get requested-by request-details)))
(request-id-idx (unwrap! (index-of? burn-requests request-id) err-request-finalized-or-revoked))
(lqstx-amount (contract-call? .token-vlqstx get-shares-to-tokens (get wrapped-amount request-details))))
(try! (is-paused-or-fail))
(asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked)
(asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised)
(try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx))
(try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) (as-contract tx-sender)))
(try! (contract-call? .token-lqstx transfer lqstx-amount (as-contract tx-sender) (get requested-by request-details) none))
(try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED })))
(try! (contract-call? .lqstx-mint-registry set-burn-requests-pending (get requested-by request-details) (pop burn-requests request-id-idx)))
(ok true)))
;; private calls
(define-private (check-err (result (response bool uint)) (prior (response bool uint)))
(match prior

View File

@@ -1,4 +1,4 @@
(define-constant err-unauthorised (err u10000))
(define-constant err-unauthorised (err u3000))
(define-map authorised-managers principal bool)
(map-set authorised-managers tx-sender true)

View File

@@ -1,19 +1,32 @@
(define-constant PENDING 0x00)
(define-constant FINALIZED 0x01)
(define-constant REVOKED 0x02)
(define-public (rebase)
(as-contract (contract-call? .lisa-rebase rebase (list .mock-strategy))))
(define-public (finalize-mint (request-id uint))
(begin
(try! (rebase))
(as-contract (try! (contract-call? .lqstx-mint-endpoint finalize-mint request-id)))
(as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 finalize-mint request-id)))
(try! (rebase))
(ok true)))
(define-public (finalize-burn (request-id uint))
(begin
(try! (rebase))
(as-contract (try! (contract-call? .lqstx-mint-endpoint finalize-burn request-id)))
(as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 finalize-burn request-id)))
(try! (rebase))
(ok true)))
(define-public (request-burn (amount uint))
(let (
(sender tx-sender)
(send-token (try! (contract-call? .token-lqstx transfer amount sender (as-contract tx-sender) none)))
(request-data (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 request-burn sender amount)))))
(match (finalize-burn (get request-id request-data))
ok-value (ok { request-id: (get request-id request-data), status: FINALIZED })
err-value (ok request-data))))
(define-public (callback (extension principal) (payload (buff 2048)))
(ok true))

View File

@@ -3,7 +3,8 @@
(define-public (execute (sender principal))
(begin
(try! (contract-call? .lisa-dao set-extensions (list
{extension: .lqstx-mint-endpoint, enabled: true}
{extension: .lqstx-mint-endpoint, enabled: false}
{extension: .lqstx-mint-endpoint-v1-01, enabled: true}
{extension: .lisa-rebase, enabled: true}
{extension: .rebase-mock, enabled: true}
{extension: .mock-strategy-manager, enabled: true}
@@ -19,9 +20,10 @@
)))
(try! (contract-call? .operators set-proposal-threshold 2))
(try! (contract-call? .lqstx-mint-endpoint set-paused false))
(try! (contract-call? .lqstx-mint-endpoint set-reward-cycle-length u200))
(try! (contract-call? .lqstx-mint-endpoint set-mint-delay u14))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-paused false))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-activation-burn-block u0))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-reward-cycle-length u200))
(try! (contract-call? .lqstx-mint-endpoint-v1-01 set-mint-delay u14))
(try! (contract-call? .mock-strategy-manager set-authorised-manager 'ST2QXSK64YQX3CQPC530K79XWQ98XFAM9W3XKEH3N true))
(try! (contract-call? .mock-strategy-manager set-authorised-manager 'ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND true))
(ok true)

View File

@@ -1,3 +1,31 @@
(define-constant PENDING 0x00)
(define-constant FINALIZED 0x01)
(define-constant REVOKED 0x02)
(define-public (rebase)
(contract-call? .lisa-rebase rebase (list .public-pools-strategy))
)
(define-public (finalize-mint (request-id uint))
(begin
(try! (rebase))
(as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 finalize-mint request-id)))
(try! (rebase))
(ok true)))
(define-public (finalize-burn (request-id uint))
(begin
(try! (rebase))
(as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 finalize-burn request-id)))
(try! (rebase))
(ok true)))
(define-public (request-burn (amount uint))
(let (
(sender tx-sender)
(send-token (try! (contract-call? .token-lqstx transfer amount sender (as-contract tx-sender) none)))
(request-data (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-01 request-burn sender amount)))))
(match (finalize-burn (get request-id request-data))
ok-value (ok { request-id: (get request-id request-data), status: FINALIZED })
err-value (ok request-data))))

View File

@@ -3,6 +3,7 @@
(rebase () (response uint uint))
(finalize-mint (uint) (response bool uint))
(finalize-burn (uint) (response bool uint))
(request-burn (uint) (response { request-id: uint, status: (buff 1) } uint))
)
)

View File

@@ -154,11 +154,6 @@ plan:
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/extensions/lqstx-vault.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-strategy-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/traits/rebase-strategy-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: stx-transfer-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -175,7 +170,7 @@ plan:
path: contracts/token-vlqstx.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-mint-endpoint
contract-name: lqstx-mint-endpoint-v1-01
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/extensions/lqstx-mint-endpoint.clar
clarity-version: 2
@@ -229,14 +224,14 @@ plan:
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/strategies/public-pools/fastpool-member.clar
clarity-version: 2
epoch: "2.4"
- id: 3
transactions:
- emulated-contract-publish:
contract-name: fastpool-member9
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/strategies/public-pools/fastpool-member.clar
clarity-version: 2
epoch: "2.4"
- id: 3
transactions:
- emulated-contract-publish:
contract-name: xverse-member1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -317,6 +312,16 @@ plan:
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/proxies/lisa-transfer-proxy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-strategy-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/deployed/rebase-strategy-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-mint-endpoint
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/deployed/lqstx-mint-endpoint.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-transfer-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -347,6 +352,14 @@ plan:
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/mocks/rebase-mock.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-strategy-trait-v1-01
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/traits/rebase-strategy-trait.clar
clarity-version: 2
epoch: "2.4"
- id: 4
transactions:
- emulated-contract-publish:
contract-name: regtest-boot
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -357,9 +370,6 @@ plan:
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: contracts/traits/sip-010-extensions-trait.clar
clarity-version: 2
epoch: "2.4"
- id: 4
transactions:
- emulated-contract-publish:
contract-name: sip-010-transferable-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM

View File

@@ -9,7 +9,7 @@ const bot = accounts.get('wallet_3')!;
const manager = accounts.get('wallet_4')!;
const contracts = {
endpoint: 'lqstx-mint-endpoint',
endpoint: 'lqstx-mint-endpoint-v1-01',
registry: 'lqstx-mint-registry',
vault: 'lqstx-vault',
lqstx: 'token-lqstx',
@@ -76,11 +76,10 @@ const requestBurn = (payload: Buffer) =>
oracle
),
tx.callPublicFn(
contracts.endpoint,
contracts.rebase1,
'request-burn',
[
Cl.uint(100e6),
Cl.contractPrincipal(simnet.deployer, contracts.rebase1),
],
user
),
@@ -89,7 +88,6 @@ const requestBurn = (payload: Buffer) =>
describe(contracts.endpoint, () => {
it('can request mint', () => {
prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true)));
const response = requestMint();
expect(response.result).toBeOk(Cl.uint(1));
});
@@ -100,7 +98,7 @@ describe(contracts.endpoint, () => {
expect(requestMint().result).toBeOk(Cl.uint(1));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
const finaliseErr = simnet.callPublicFn(
@@ -154,7 +152,7 @@ describe(contracts.endpoint, () => {
expect(responses[1].result).toBeOk(Cl.bool(true));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
simnet.mineEmptyBlocks(144); // mint-delay
@@ -174,7 +172,7 @@ describe(contracts.endpoint, () => {
expect(requestMint().result).toBeOk(Cl.uint(1));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
simnet.mineEmptyBlocks(144); // mint-delay
@@ -197,7 +195,7 @@ describe(contracts.endpoint, () => {
expect(requestMint().result).toBeOk(Cl.uint(1));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
simnet.mineEmptyBlocks(144); // mint-delay
@@ -254,7 +252,7 @@ describe(contracts.endpoint, () => {
expect(requestMint().result).toBeOk(Cl.uint(1));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
simnet.mineEmptyBlocks(144); // mint-delay
@@ -318,7 +316,7 @@ describe(contracts.endpoint, () => {
).result.buffer;
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine - 100);
let responses = simnet.mineBlock([
@@ -360,11 +358,10 @@ describe(contracts.endpoint, () => {
bot
),
tx.callPublicFn(
contracts.endpoint,
contracts.rebase1,
'request-burn',
[
Cl.uint(100e6),
Cl.contractPrincipal(simnet.deployer, contracts.rebase1),
],
user
),
@@ -427,7 +424,7 @@ describe(contracts.endpoint, () => {
expect(requestMint().result).toBeOk(Cl.uint(1));
const cycle = simnet.callReadOnlyFn(contracts.endpoint, 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user).result.value.value;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-stacks-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
const blocksToMine = Number(simnet.callReadOnlyFn(contracts.endpoint, 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle + 1n)], user).result.value) - simnet.blockHeight;
simnet.mineEmptyBlocks(blocksToMine); // go to the next cycle
const finaliseErr = simnet.callPublicFn(