From 9a97a7460ca318a11fb4017fd113e04ee9754bc4 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Wed, 20 Mar 2024 09:58:37 +0800 Subject: [PATCH 01/32] fix: get-reward-cycle measures prepare to prepare, not end to end --- contracts/extensions/lqstx-mint-endpoint.clar | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 2725804..ac84ab8 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -25,13 +25,14 @@ (define-data-var paused bool true) (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts -;; corresponds to `first-burnchain-block-height` and `pox-reward-cycle-length` in pox-3 ;; __IF_MAINNET__ (define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) +(define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) ;; (define-constant activation-burn-block u0) ;; (define-constant reward-cycle-length u200) +;; (define-constant prepare-cycle-length u100) ;; __ENDIF__ (define-data-var use-whitelist bool false) @@ -45,7 +46,7 @@ (define-read-only (is-paused) (var-get paused)) -(define-read-only (is-paused-or-fail) +(define-read-only (is-not-paused-or-fail) (ok (asserts! (not (is-paused)) err-paused))) (define-read-only (get-mint-request-or-fail (request-id uint)) @@ -85,9 +86,10 @@ (asserts! (>= (stx-get-balance .lqstx-vault) vaulted-amount) err-request-pending) (ok { vaulted-amount: vaulted-amount, request-id-idx: request-id-idx }))) +;; @dev get-reward-cycle measures prepare to prepare, not end to end (define-read-only (get-reward-cycle (burn-block uint)) (if (>= burn-block activation-burn-block) - (some (/ (- burn-block activation-burn-block) reward-cycle-length)) + (some (/ (- (+ burn-block prepare-cycle-length) activation-burn-block) reward-cycle-length)) none)) (define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) @@ -108,7 +110,7 @@ (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)) + (try! (is-not-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))) @@ -121,7 +123,7 @@ (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)) + (try! (is-not-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) })))) @@ -136,7 +138,7 @@ (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)) + (try! (is-not-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)) @@ -180,7 +182,7 @@ (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-not-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 }))) @@ -198,7 +200,7 @@ (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! (is-not-paused-or-fail)) (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)) @@ -212,7 +214,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-not-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))) From 0c596fd38632714557ed69458985f7bbab786b33 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Wed, 20 Mar 2024 10:35:29 +0800 Subject: [PATCH 02/32] get-request-cycle vs. get-reward-cycle --- Clarinet.toml | 14 +++++++- contracts/extensions/lisa-rebase.clar | 2 +- contracts/extensions/lqstx-mint-endpoint.clar | 23 ++++++++++--- contracts/mocks/rebase-mock.clar | 8 ++--- contracts/regtest-boot.clar | 8 ++--- contracts/rules/rebase-1.clar | 8 ++--- contracts/simnet-boot.clar | 12 +++---- deployments/default.simnet-plan.yaml | 32 +++++++++++++------ ...tx-mint-endpoint-with-public-pools.test.ts | 6 ++-- tests/lqstx-mint-endpoint.test.ts | 4 +-- tests/operators.test.ts | 4 +-- 11 files changed, 80 insertions(+), 41 deletions(-) diff --git a/Clarinet.toml b/Clarinet.toml index 87158f8..f57bae7 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -175,10 +175,14 @@ epoch = 2.4 path = "contracts/extensions/public-pools-strategy-manager.clar" epoch = 2.4 -[contracts.lqstx-mint-endpoint-v1-01] +[contracts.lqstx-mint-endpoint-v1-02] path = "contracts/extensions/lqstx-mint-endpoint.clar" epoch = 2.4 +[contracts.lqstx-mint-endpoint-v1-01] +path = "contracts/deployed/lqstx-mint-endpoint-v1-01.clar" +epoch = 2.4 + [contracts.lqstx-mint-endpoint] path = "contracts/deployed/lqstx-mint-endpoint.clar" epoch = 2.4 @@ -200,10 +204,18 @@ path = "contracts/token-lisa.clar" epoch = 2.4 [contracts.lisa-rebase] +path = "contracts/deployed/lisa-rebase.clar" +epoch = 2.4 + +[contracts.lisa-rebase-v1-02] path = "contracts/extensions/lisa-rebase.clar" epoch = 2.4 [contracts.rebase-1] +path = "contracts/deployed/rebase-1.clar" +epoch = 2.4 + +[contracts.rebase-1-v1-02] path = "contracts/rules/rebase-1.clar" epoch = 2.4 diff --git a/contracts/extensions/lisa-rebase.clar b/contracts/extensions/lisa-rebase.clar index 16bea8c..db74bcf 100644 --- a/contracts/extensions/lisa-rebase.clar +++ b/contracts/extensions/lisa-rebase.clar @@ -14,7 +14,7 @@ ) (define-public (rebase (strategies (list 20 ))) - (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)))) + (let ((total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts strategies (ok u0)))) (contract-call? .lqstx-mint-endpoint-v1-02 get-mint-requests-pending-amount)))) (try! (is-dao-or-extension)) (as-contract (try! (contract-call? .token-lqstx set-reserve total-stx))) (ok total-stx) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index ac84ab8..1b70e4c 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -24,6 +24,7 @@ (define-data-var paused bool true) (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts +(define-data-var request-cutoff uint u100) ;; request must be made 100 blocks before prepare stage starts ;; __IF_MAINNET__ (define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) @@ -86,10 +87,16 @@ (asserts! (>= (stx-get-balance .lqstx-vault) vaulted-amount) err-request-pending) (ok { vaulted-amount: vaulted-amount, request-id-idx: request-id-idx }))) -;; @dev get-reward-cycle measures prepare to prepare, not end to end +;; @dev get-reward-cycle measures end to end (define-read-only (get-reward-cycle (burn-block uint)) (if (>= burn-block activation-burn-block) - (some (/ (- (+ burn-block prepare-cycle-length) activation-burn-block) reward-cycle-length)) + (some (/ (- burn-block activation-burn-block) reward-cycle-length)) + none)) + +;; @dev get-request-cycle measures request-cutoff to request-cutoff +(define-read-only (get-request-cycle (burn-block uint)) + (if (>= burn-block activation-burn-block) + (some (/ (- (+ burn-block prepare-cycle-length (var-get request-cutoff)) activation-burn-block) reward-cycle-length)) none)) (define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) @@ -98,6 +105,9 @@ (define-read-only (get-mint-delay) (var-get mint-delay)) +(define-read-only (get-request-cutoff) + (var-get request-cutoff)) + (define-read-only (is-whitelisted-or-mint-for-all (user principal)) (or (not (var-get use-whitelist)) (default-to false (map-get? whitelisted user)))) @@ -107,7 +117,7 @@ (define-public (request-mint (amount uint)) (let ( (sender tx-sender) - (cycle (unwrap-panic (get-reward-cycle burn-block-height))) + (cycle (unwrap-panic (get-request-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-not-paused-or-fail)) @@ -175,6 +185,11 @@ (try! (is-dao-or-extension)) (ok (var-set mint-delay new-delay)))) +(define-public (set-request-cutoff (new-cutoff uint)) + (begin + (try! (is-dao-or-extension)) + (ok (var-set request-cutoff new-cutoff)))) + ;; privileged calls (define-public (finalize-mint (request-id uint)) @@ -196,7 +211,7 @@ (define-public (request-burn (sender principal) (amount uint)) (let ( ;; @dev requested-at not used for burn - (cycle (unwrap-panic (get-reward-cycle burn-block-height))) + (cycle (unwrap-panic (get-request-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)))) diff --git a/contracts/mocks/rebase-mock.clar b/contracts/mocks/rebase-mock.clar index 97739c5..3ddce4e 100644 --- a/contracts/mocks/rebase-mock.clar +++ b/contracts/mocks/rebase-mock.clar @@ -6,19 +6,19 @@ (define-constant REVOKED 0x02) (define-public (rebase) - (as-contract (contract-call? .lisa-rebase rebase (list .mock-strategy)))) + (as-contract (contract-call? .lisa-rebase-v1-02 rebase (list .mock-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))) + (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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))) + (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 finalize-burn request-id))) (try! (rebase)) (ok true))) @@ -26,7 +26,7 @@ (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))))) + (request-data (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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)))) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index 25b06ee..1cebead 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -7,8 +7,8 @@ (begin (try! (contract-call? .lisa-dao set-extensions (list {extension: .lqstx-mint-endpoint, enabled: false} - {extension: .lqstx-mint-endpoint-v1-01, enabled: true} - {extension: .lisa-rebase, enabled: true} + {extension: .lqstx-mint-endpoint-v1-02, enabled: true} + {extension: .lisa-rebase-v1-02, enabled: true} {extension: .rebase-mock, enabled: true} {extension: .mock-strategy-manager, enabled: true} {extension: .lqstx-vault, enabled: true} @@ -24,8 +24,8 @@ ))) (try! (contract-call? .operators set-proposal-threshold 2)) - (try! (contract-call? .lqstx-mint-endpoint-v1-01 set-paused false)) - (try! (contract-call? .lqstx-mint-endpoint-v1-01 set-mint-delay u14)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-paused false)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 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) diff --git a/contracts/rules/rebase-1.clar b/contracts/rules/rebase-1.clar index 3a3baeb..ca16bca 100644 --- a/contracts/rules/rebase-1.clar +++ b/contracts/rules/rebase-1.clar @@ -7,20 +7,20 @@ (define-constant REVOKED 0x02) (define-public (rebase) - (contract-call? .lisa-rebase rebase (list .public-pools-strategy)) + (contract-call? .lisa-rebase-v1-02 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))) + (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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))) + (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 finalize-burn request-id))) (try! (rebase)) (ok true))) @@ -28,7 +28,7 @@ (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))))) + (request-data (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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)))) diff --git a/contracts/simnet-boot.clar b/contracts/simnet-boot.clar index 006bc78..9248f98 100644 --- a/contracts/simnet-boot.clar +++ b/contracts/simnet-boot.clar @@ -7,13 +7,13 @@ (begin (try! (contract-call? .lisa-dao set-extensions (list { extension: .lqstx-mint-endpoint, enabled: false } - { extension: .lqstx-mint-endpoint-v1-01, enabled: true } + { extension: .lqstx-mint-endpoint-v1-02, enabled: true } { extension: .lqstx-vault, enabled: true } { extension: .treasury, enabled: true } { extension: .token-vesting, enabled: true } { extension: .public-pools-strategy-manager, enabled: true } - { extension: .lisa-rebase, enabled: true } - { extension: .rebase-1, enabled: true } + { extension: .lisa-rebase-v1-02, enabled: true } + { extension: .rebase-1-v1-02, enabled: true } { extension: .operators, enabled: true } ))) @@ -40,8 +40,8 @@ ))) ;; Enable whitelist - (try! (contract-call? .lqstx-mint-endpoint-v1-01 set-use-whitelist false)) - (try! (contract-call? .lqstx-mint-endpoint-v1-01 set-whitelisted-many + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist false)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-whitelisted-many (list 'SP3BQ65DRM8DMTYDD5HWMN60EYC0JFS5NC2V5CWW7 'SP2VZBR9GCVM33BN0WXA05VJP6QV7CJ3Z3SQKJ5HH @@ -56,7 +56,7 @@ true true ))) - (try! (contract-call? .lqstx-mint-endpoint-v1-01 set-paused false)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-paused false)) (ok true) ) ) diff --git a/deployments/default.simnet-plan.yaml b/deployments/default.simnet-plan.yaml index 398380a..9dcdf2d 100644 --- a/deployments/default.simnet-plan.yaml +++ b/deployments/default.simnet-plan.yaml @@ -54,9 +54,6 @@ plan: emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE path: "./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar" clarity-version: 1 - epoch: "2.0" - - id: 1 - transactions: - emulated-contract-publish: contract-name: trait-sip-010 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -102,8 +99,8 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts_modules/alex_v1/traits/trait-vault.clar clarity-version: 1 - epoch: "2.05" - - id: 2 + epoch: "2.1" + - id: 1 transactions: - emulated-contract-publish: contract-name: pox-pools-1-cycle-v2 @@ -168,7 +165,7 @@ plan: - emulated-contract-publish: contract-name: lqstx-mint-endpoint-v1-01 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM - path: contracts/extensions/lqstx-mint-endpoint.clar + path: contracts/deployed/lqstx-mint-endpoint-v1-01.clar clarity-version: 2 - emulated-contract-publish: contract-name: operators @@ -231,7 +228,7 @@ plan: path: contracts/strategies/public-pools/xverse-member.clar clarity-version: 2 epoch: "2.4" - - id: 3 + - id: 2 transactions: - emulated-contract-publish: contract-name: xverse-member10 @@ -301,6 +298,16 @@ plan: - emulated-contract-publish: contract-name: lisa-rebase emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/deployed/lisa-rebase.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: lqstx-mint-endpoint-v1-02 + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/extensions/lqstx-mint-endpoint.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: lisa-rebase-v1-02 + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/extensions/lisa-rebase.clar clarity-version: 2 - emulated-contract-publish: @@ -341,8 +348,16 @@ plan: - emulated-contract-publish: contract-name: rebase-1 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/deployed/rebase-1.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: rebase-1-v1-02 + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/rules/rebase-1.clar clarity-version: 2 + epoch: "2.4" + - id: 3 + transactions: - emulated-contract-publish: contract-name: rebase-mock emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -358,9 +373,6 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/regtest-boot.clar clarity-version: 2 - epoch: "2.4" - - id: 4 - transactions: - emulated-contract-publish: contract-name: simnet-boot emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index 486227e..470e294 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -14,15 +14,15 @@ const operator = accounts.get('wallet_4')!; const user2 = accounts.get('wallet_5')!; const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-01', + endpoint: 'lqstx-mint-endpoint-v1-02', registry: 'lqstx-mint-registry', vault: 'lqstx-vault', lqstx: 'token-lqstx', vlqstx: 'token-vlqstx', wstx: 'token-wstx', strategy: 'public-pools-strategy', - rebase: 'lisa-rebase', - rebase1: 'rebase-1', + rebase: 'lisa-rebase-v1-02', + rebase1: 'rebase-1-v1-02', amm: 'amm-swap-pool-v1-1', wlqstx: 'token-wlqstx', dao: 'lisa-dao', diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 88c2a93..26830a2 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -12,14 +12,14 @@ const bot = accounts.get('wallet_3')!; const manager = accounts.get('wallet_4')!; const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-01', + endpoint: 'lqstx-mint-endpoint-v1-02', registry: 'lqstx-mint-registry', vault: 'lqstx-vault', lqstx: 'token-lqstx', vlqstx: 'token-vlqstx', wstx: 'token-wstx', strategy: 'mock-strategy', - rebase: 'lisa-rebase', + rebase: 'lisa-rebase-v1-02', rebase1: 'rebase-mock', amm: 'amm-swap-pool-v1-1', wlqstx: 'token-wlqstx', diff --git a/tests/operators.test.ts b/tests/operators.test.ts index 0e9a808..dc9641c 100644 --- a/tests/operators.test.ts +++ b/tests/operators.test.ts @@ -13,14 +13,14 @@ const manager = accounts.get('wallet_4')!; const operator3 = accounts.get('wallet_5')!; const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-01', + endpoint: 'lqstx-mint-endpoint-v1-02', registry: 'lqstx-mint-registry', vault: 'lqstx-vault', lqstx: 'token-lqstx', vlqstx: 'token-vlqstx', wstx: 'token-wstx', strategy: 'mock-strategy', - rebase: 'lisa-rebase', + rebase: 'lisa-rebase-v1-02', rebase1: 'rebase-mock', amm: 'amm-swap-pool-v1-1', wlqstx: 'token-wlqstx', From 1de6794b6a5d77e50999d224bda68d297bb87cd2 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Wed, 20 Mar 2024 10:36:07 +0800 Subject: [PATCH 03/32] lip001; move old contracts to deployed --- contracts/deployed/lisa-rebase.clar | 22 ++ .../deployed/lqstx-mint-endpoint-v1-01.clar | 243 ++++++++++++++++++ contracts/deployed/rebase-1.clar | 34 +++ contracts/proposals/lip001.clar | 39 +++ 4 files changed, 338 insertions(+) create mode 100644 contracts/deployed/lisa-rebase.clar create mode 100644 contracts/deployed/lqstx-mint-endpoint-v1-01.clar create mode 100644 contracts/deployed/rebase-1.clar create mode 100644 contracts/proposals/lip001.clar diff --git a/contracts/deployed/lisa-rebase.clar b/contracts/deployed/lisa-rebase.clar new file mode 100644 index 0000000..16bea8c --- /dev/null +++ b/contracts/deployed/lisa-rebase.clar @@ -0,0 +1,22 @@ + +;; SPDX-License-Identifier: BUSL-1.1 + +(use-trait strategy-trait .strategy-trait.strategy-trait) + +(define-constant err-unauthorised (err u3000)) + +(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-private (sum-strategy-amounts (strategy ) (accumulator (response uint uint))) + (ok (+ (try! (contract-call? strategy get-amount-in-strategy)) (try! accumulator))) +) + +(define-public (rebase (strategies (list 20 ))) + (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) + ) +) diff --git a/contracts/deployed/lqstx-mint-endpoint-v1-01.clar b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar new file mode 100644 index 0000000..ac84ab8 --- /dev/null +++ b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar @@ -0,0 +1,243 @@ + +;; SPDX-License-Identifier: BUSL-1.1 + +;; +;; lqstx-mint-endpoint-v1-01 +;; + +;; __IF_MAINNET__ +(use-trait sip-010-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait) +;; (use-trait sip-010-trait .sip-010-trait.sip-010-trait) +;; __ENDIF__ + +(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 u432) ;; mint available 3 day after cycle starts + +;; __IF_MAINNET__ +(define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) +(define-constant activation-burn-block (get first-burnchain-block-height pox-info)) +(define-constant reward-cycle-length (get reward-cycle-length pox-info)) +(define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) +;; (define-constant activation-burn-block u0) +;; (define-constant reward-cycle-length u200) +;; (define-constant prepare-cycle-length u100) +;; __ENDIF__ + +(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-not-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! (>= 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 +(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 get-reward-cycle measures prepare to prepare, not end to end +(define-read-only (get-reward-cycle (burn-block uint)) + (if (>= burn-block activation-burn-block) + (some (/ (- (+ burn-block prepare-cycle-length) activation-burn-block) reward-cycle-length)) + none)) + +(define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) + (+ activation-burn-block (* 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)))) + +;; 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-not-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-not-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-not-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 + (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)))) + +;; privileged calls + +(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-not-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 (request-burn (sender principal) (amount uint)) + (let ( + ;; @dev requested-at not used for burn + (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-not-paused-or-fail)) + (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)))) + (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 ( + (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-not-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))) + +;; private calls + +(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))) + diff --git a/contracts/deployed/rebase-1.clar b/contracts/deployed/rebase-1.clar new file mode 100644 index 0000000..3a3baeb --- /dev/null +++ b/contracts/deployed/rebase-1.clar @@ -0,0 +1,34 @@ + +;; SPDX-License-Identifier: BUSL-1.1 + + +(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)))) diff --git a/contracts/proposals/lip001.clar b/contracts/proposals/lip001.clar new file mode 100644 index 0000000..57e9cd5 --- /dev/null +++ b/contracts/proposals/lip001.clar @@ -0,0 +1,39 @@ + +;; SPDX-License-Identifier: BUSL-1.1 + +(impl-trait .proposal-trait.proposal-trait) + +(define-public (execute (sender principal)) + (begin + (try! (contract-call? .lisa-dao set-extensions (list + { extension: .lqstx-mint-endpoint-v1-01, enabled: false } + { extension: .lqstx-mint-endpoint-v1-02, enabled: true } + { extension: .lisa-rebase, enabled: false } + { extension: .rebase-1, enabled: false } + { extension: .lisa-rebase-v1-02, enabled: true } + { extension: .rebase-1-v1-02, enabled: true } + ))) + + ;; Enable whitelist + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist true)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-whitelisted-many + (list + 'SP3BQ65DRM8DMTYDD5HWMN60EYC0JFS5NC2V5CWW7 + 'SP2VZBR9GCVM33BN0WXA05VJP6QV7CJ3Z3SQKJ5HH + 'SP12BFYTH3NJ6N63KE0S50GHSYV0M91NGQND2B704 + 'SPGAB1P3YV109E22KXFJYM63GK0G21BYX50CQ80B + 'SPFJVM9Y1A4KJ31T8ZBDESZH36YGPDAZ9WXEFC53 + 'SPHFAXDZVFHMY8YR3P9J7ZCV6N89SBET203ZAY25 + ) + (list + true + true + true + true + true + true + ))) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-paused false)) + (ok true) + ) +) From af9cb1a1c568ec055d7219fb60194356fc6f7e02 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Wed, 20 Mar 2024 10:44:36 +0800 Subject: [PATCH 04/32] get-first-burn-block-in-reward-cycle --- contracts/extensions/lqstx-mint-endpoint.clar | 7 +++++-- deployments/default.simnet-plan.yaml | 11 +++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 1b70e4c..8a12281 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -93,14 +93,17 @@ (some (/ (- burn-block activation-burn-block) reward-cycle-length)) none)) +(define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) + (+ activation-burn-block (* reward-cycle-length reward-cycle))) + ;; @dev get-request-cycle measures request-cutoff to request-cutoff (define-read-only (get-request-cycle (burn-block uint)) (if (>= burn-block activation-burn-block) (some (/ (- (+ burn-block prepare-cycle-length (var-get request-cutoff)) activation-burn-block) reward-cycle-length)) none)) -(define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) - (+ activation-burn-block (* reward-cycle-length reward-cycle))) +(define-read-only (get-first-burn-block-in-request-cycle (reward-cycle uint)) + (- (+ activation-burn-block (* reward-cycle-length reward-cycle)) prepare-cycle-length (var-get request-cutoff))) (define-read-only (get-mint-delay) (var-get mint-delay)) diff --git a/deployments/default.simnet-plan.yaml b/deployments/default.simnet-plan.yaml index 9dcdf2d..33b7227 100644 --- a/deployments/default.simnet-plan.yaml +++ b/deployments/default.simnet-plan.yaml @@ -54,6 +54,9 @@ plan: emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE path: "./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar" clarity-version: 1 + epoch: "2.0" + - id: 1 + transactions: - emulated-contract-publish: contract-name: trait-sip-010 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -99,8 +102,8 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts_modules/alex_v1/traits/trait-vault.clar clarity-version: 1 - epoch: "2.1" - - id: 1 + epoch: "2.05" + - id: 2 transactions: - emulated-contract-publish: contract-name: pox-pools-1-cycle-v2 @@ -228,7 +231,7 @@ plan: path: contracts/strategies/public-pools/xverse-member.clar clarity-version: 2 epoch: "2.4" - - id: 2 + - id: 3 transactions: - emulated-contract-publish: contract-name: xverse-member10 @@ -356,7 +359,7 @@ plan: path: contracts/rules/rebase-1.clar clarity-version: 2 epoch: "2.4" - - id: 3 + - id: 4 transactions: - emulated-contract-publish: contract-name: rebase-mock From 791336761911d426969f2eec408e3db8f4f07f9c Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Wed, 20 Mar 2024 11:13:18 +0800 Subject: [PATCH 05/32] feat: shorting it to u10 on regtest --- contracts/extensions/lqstx-mint-endpoint.clar | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 8a12281..11fbacd 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -24,13 +24,14 @@ (define-data-var paused bool true) (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts -(define-data-var request-cutoff uint u100) ;; request must be made 100 blocks before prepare stage starts ;; __IF_MAINNET__ +(define-data-var request-cutoff uint u100) ;; request must be made 100 blocks before prepare stage starts (define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) (define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) +;; (define-data-var request-cutoff uint u10) ;; (define-constant activation-burn-block u0) ;; (define-constant reward-cycle-length u200) ;; (define-constant prepare-cycle-length u100) From c7f1e30e612242b7b119077d1403cc7a988a1bd9 Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Wed, 20 Mar 2024 11:38:42 +0800 Subject: [PATCH 06/32] feat: shorter prepare-cycle-length to u10 on regtest --- contracts/extensions/lqstx-mint-endpoint.clar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 11fbacd..c6ef3d6 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -34,7 +34,7 @@ ;; (define-data-var request-cutoff uint u10) ;; (define-constant activation-burn-block u0) ;; (define-constant reward-cycle-length u200) -;; (define-constant prepare-cycle-length u100) +;; (define-constant prepare-cycle-length u10) ;; __ENDIF__ (define-data-var use-whitelist bool false) From efa7a3a616a27665ef71ee4bd695fe953d33ad91 Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Wed, 20 Mar 2024 11:44:42 +0800 Subject: [PATCH 07/32] feat: use same rebase-1-v1-02 but stub out the implementation with rebase-mock --- contracts/regtest-boot.clar | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index 1cebead..d97aa97 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -9,7 +9,7 @@ {extension: .lqstx-mint-endpoint, enabled: false} {extension: .lqstx-mint-endpoint-v1-02, enabled: true} {extension: .lisa-rebase-v1-02, enabled: true} - {extension: .rebase-mock, enabled: true} + {extension: .rebase-1-v1-02, enabled: true} {extension: .mock-strategy-manager, enabled: true} {extension: .lqstx-vault, enabled: true} {extension: .operators, enabled: true} From 823a62554f9f7fc168fab14173a425ea9af0fce5 Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 09:08:02 +0100 Subject: [PATCH 08/32] chore: add test for request cycle --- contracts/regtest-boot.clar | 2 +- deployments/default.simnet-plan.yaml | 11 +++----- tests/lqstx-mint-endpoint.test.ts | 40 ++++++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index d97aa97..1cebead 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -9,7 +9,7 @@ {extension: .lqstx-mint-endpoint, enabled: false} {extension: .lqstx-mint-endpoint-v1-02, enabled: true} {extension: .lisa-rebase-v1-02, enabled: true} - {extension: .rebase-1-v1-02, enabled: true} + {extension: .rebase-mock, enabled: true} {extension: .mock-strategy-manager, enabled: true} {extension: .lqstx-vault, enabled: true} {extension: .operators, enabled: true} diff --git a/deployments/default.simnet-plan.yaml b/deployments/default.simnet-plan.yaml index 33b7227..9dcdf2d 100644 --- a/deployments/default.simnet-plan.yaml +++ b/deployments/default.simnet-plan.yaml @@ -54,9 +54,6 @@ plan: emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE path: "./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar" clarity-version: 1 - epoch: "2.0" - - id: 1 - transactions: - emulated-contract-publish: contract-name: trait-sip-010 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -102,8 +99,8 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts_modules/alex_v1/traits/trait-vault.clar clarity-version: 1 - epoch: "2.05" - - id: 2 + epoch: "2.1" + - id: 1 transactions: - emulated-contract-publish: contract-name: pox-pools-1-cycle-v2 @@ -231,7 +228,7 @@ plan: path: contracts/strategies/public-pools/xverse-member.clar clarity-version: 2 epoch: "2.4" - - id: 3 + - id: 2 transactions: - emulated-contract-publish: contract-name: xverse-member10 @@ -359,7 +356,7 @@ plan: path: contracts/rules/rebase-1.clar clarity-version: 2 epoch: "2.4" - - id: 4 + - id: 3 transactions: - emulated-contract-publish: contract-name: rebase-mock diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 26830a2..44d3c65 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -1,8 +1,7 @@ - // SPDX-License-Identifier: BUSL-1.1 import { tx } from '@hirosystems/clarinet-sdk'; -import { Cl, ResponseOkCV, UIntCV } from '@stacks/transactions'; +import { Cl, ResponseOkCV, UIntCV, cvToString } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; const accounts = simnet.getAccounts(); @@ -64,6 +63,23 @@ const getRewardCycle = () => { ).value.value; }; +const getRequestCycle = () => { + return ( + simnet.callReadOnlyFn( + contracts.endpoint, + 'get-request-cycle', + [Cl.uint(simnet.blockHeight)], + user + ).result as ResponseOkCV + ).value.value; +}; + +const getRequestCutoff = () => { + return ( + simnet.callReadOnlyFn(contracts.endpoint, 'get-request-cutoff', [], user) + .result as ResponseOkCV + ).value; +}; const getBlocksToStartOfCycle = (cycle: bigint) => { return ( Number( @@ -356,4 +372,24 @@ describe(contracts.endpoint, () => { expect(responses[0].result).toBeErr(Cl.uint(1001)); expect(responses[1].result).toBeOk(Cl.bool(true)); }); + + it('request cycle respects cutoff', () => { + expect(getRequestCycle()).toBe(0n); + // cycle length - prepare cycle length - cutoff - blocks for deployment + simnet.mineEmptyBlocks(1050 - 50 - 100 - 4 - 1); + // we are at the end of request cycle 0 + expect(simnet.blockHeight).toBe(899); + expect(getRequestCycle()).toBe(0n); + + simnet.mineEmptyBlocks(1050); // cycle length + // we are at end of request cycle 1 + expect(simnet.blockHeight).toBe(1949); + expect(getRequestCycle()).toBe(1n); + + simnet.mineEmptyBlocks(1); + // we are at beginning of request cycle 2 + // that is 1050 + 1050 - 50 - 100 + expect(simnet.blockHeight).toBe(1950); + expect(getRequestCycle()).toBe(2n); + }); }); From 12ff1a680da3502fb701e1b11d3921dcb34e8008 Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 10:39:51 +0100 Subject: [PATCH 09/32] chore: add test for request mint event --- tests/lqstx-mint-endpoint.test.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 44d3c65..8618a19 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import { tx } from '@hirosystems/clarinet-sdk'; -import { Cl, ResponseOkCV, UIntCV, cvToString } from '@stacks/transactions'; +import { Cl, ResponseOkCV, TupleCV, UIntCV } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; const accounts = simnet.getAccounts(); @@ -374,9 +374,11 @@ describe(contracts.endpoint, () => { }); it('request cycle respects cutoff', () => { + prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); + expect(getRequestCycle()).toBe(0n); - // cycle length - prepare cycle length - cutoff - blocks for deployment - simnet.mineEmptyBlocks(1050 - 50 - 100 - 4 - 1); + // cycle length - prepare cycle length - cutoff - blocks for deployment and prepare + simnet.mineEmptyBlocks(1050 - 50 - 100 - 6); // we are at the end of request cycle 0 expect(simnet.blockHeight).toBe(899); expect(getRequestCycle()).toBe(0n); @@ -391,5 +393,14 @@ describe(contracts.endpoint, () => { // that is 1050 + 1050 - 50 - 100 expect(simnet.blockHeight).toBe(1950); expect(getRequestCycle()).toBe(2n); + + const response = requestMint(); + console.log(response.events[1].data); + expect(response.result).toBeOk(Cl.uint(1)); + expect(response.events[0].event).toBe('stx_transfer_event'); + expect(response.events[1].event).toBe('print_event'); + expect( + ((response.events[1].data.value as TupleCV).data.details as TupleCV).data['requested-at'] + ).toBeUint(2); }); }); From 3301d28f196dfa1f1af503cc8e6dcae3f51659b6 Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 14:44:23 +0100 Subject: [PATCH 10/32] feat: add error codes --- README.md | 123 ++++++++++++++++++ contracts/extensions/lqstx-mint-endpoint.clar | 12 +- package.json | 1 + scripts/error-codes.ts | 92 +++++++++++++ scripts/logErrors.js | 5 + ...tx-mint-endpoint-with-public-pools.test.ts | 22 ++-- tests/lqstx-mint-endpoint.test.ts | 20 +-- 7 files changed, 248 insertions(+), 27 deletions(-) create mode 100644 README.md create mode 100644 scripts/error-codes.ts create mode 100644 scripts/logErrors.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c599a1 --- /dev/null +++ b/README.md @@ -0,0 +1,123 @@ +# Liquid Stacking (LISA) + +## Deployment + +1. npm run + +## Errors + +The LISA protocol contracts each have their own error space. All protocol errors +are in the form `(err uint)` and they are unique across all contracts. + +### Error space + +| Group | Error space | Description | +| ------------- | ----------- | ---------------------------------------------- | +| Dao | 1XXX | Errors related to the dao. | +| Operators | 1XXX | Errors related to the operators. | +| Strategy | 2XXX | Errors related to stacking strategy. | +| Permissions | 3XXX | Errors related to governance of the dao. | +| Token | 3XXX | Errors coming directly from the tokens. | +| Proxy | 4XXX | Errors related to proxy contracts. | +| Pool members | 5XXX | Errors related to stacking pool members. | +| Wrapped token | 6XXX | Errors coming directly from the wrapped token. | +| Mint Endpoint | 7XXX | Errors coming directly from the mint endpoint. | +| Vesting | 9XXX | Errors coming directly from vesting. | +| Pools | 4XX/5XX/6XX | Errors coming public stacking pools. | +| Assets | 1/2/3/4 | Errors coming for native Clarity assets. | + +### Error table + + +| Contract | Constant | Value | Description | +|-------------------------------|----------------------------------|-------------|-------------| +| lisa-dao | err-unauthorised | (err u1000) | | +| lqstx-mint-endpoint | err-unauthorised | (err u1000) | | +| lqstx-mint-endpoint-v1-01 | err-unauthorised | (err u1000) | | +| lqstx-vault | err-unauthorised | (err u1000) | | +| operators | err-unauthorised | (err u1000) | | +| token-vesting | err-unauthorised | (err u1000) | | +| token-wlqstx | err-not-authorized | (err u1000) | | +| treasury | err-unauthorised | (err u1000) | | +| lisa-dao | err-already-executed | (err u1001) | | +| lqstx-mint-endpoint | err-paused | (err u1001) | | +| lqstx-mint-endpoint-v1-01 | err-paused | (err u1001) | | +| operators | err-not-operator | (err u1001) | | +| lisa-dao | err-invalid-extension | (err u1002) | | +| operators | err-already-signalled | (err u1002) | | +| operators | err-proposal-expired | (err u1003) | | +| operators | err-unknown-proposal | (err u1004) | | +| operators | err-reused-proposal | (err u1005) | | +| lqstx-mint-endpoint | err-request-pending | (err u1006) | | +| lqstx-mint-endpoint-v1-01 | err-request-pending | (err u1006) | | +| lqstx-mint-endpoint | err-request-finalized-or-revoked | (err u1007) | | +| lqstx-mint-endpoint-v1-01 | err-request-finalized-or-revoked | (err u1007) | | +| lqstx-mint-endpoint | err-not-whitelisted | (err u1008) | | +| lqstx-mint-endpoint-v1-01 | err-not-whitelisted | (err u1008) | | +| lqstx-mint-registry | err-unknown-request-id | (err u1008) | | +| public-pools-strategy | err-not-vault-caller | (err u2000) | | +| public-pools-strategy | err-invalid-payload | (err u2001) | | +| lisa-rebase | err-unauthorised | (err u3000) | | +| lisa-rebase-v1-02 | err-unauthorised | (err u3000) | | +| lqstx-mint-endpoint-v1-02 | err-unauthorised | (err u3000) | | +| lqstx-mint-registry | err-unauthorised | (err u3000) | | +| public-pools-strategy-manager | err-unauthorised | (err u3000) | | +| token-lisa | err-unauthorised | (err u3000) | | +| token-lqstx | err-unauthorised | (err u3000) | | +| token-vlqstx | err-unauthorised | (err u3000) | | +| token-wlqstx | err-transfer-failed | (err u3000) | | +| token-lqstx | err-invalid-amount | (err u3001) | | +| token-lisa | err-not-token-owner | (err u4) | | +| lisa-transfer-proxy | err-invalid-payload | (err u4000) | | +| lqstx-transfer-proxy | err-invalid-payload | (err u4000) | | +| stx-transfer-many-proxy | err-invalid-payload | (err u4000) | | +| stx-transfer-proxy | err-invalid-payload | (err u4000) | | +| pox-fast-pool-v2 | err-unauthorized | (err u401) | | +| pox-fast-pool-v2 | err-forbidden | (err u403) | | +| pox-pools-1-cycle-v2 | err-not-found | (err u404) | | +| pox-fast-pool-v2 | err-too-early | (err u500) | | +| pox-pools-1-cycle-v2 | err-non-positive-amount | (err u500) | | +| fastpool-member1 | err-unauthorised | (err u5000) | | +| fastpool-member10 | err-unauthorised | (err u5000) | | +| fastpool-member2 | err-unauthorised | (err u5000) | | +| fastpool-member3 | err-unauthorised | (err u5000) | | +| fastpool-member4 | err-unauthorised | (err u5000) | | +| fastpool-member5 | err-unauthorised | (err u5000) | | +| fastpool-member6 | err-unauthorised | (err u5000) | | +| fastpool-member7 | err-unauthorised | (err u5000) | | +| fastpool-member8 | err-unauthorised | (err u5000) | | +| fastpool-member9 | err-unauthorised | (err u5000) | | +| xverse-member1 | err-unauthorised | (err u5000) | | +| xverse-member10 | err-unauthorised | (err u5000) | | +| xverse-member2 | err-unauthorised | (err u5000) | | +| xverse-member3 | err-unauthorised | (err u5000) | | +| xverse-member4 | err-unauthorised | (err u5000) | | +| xverse-member5 | err-unauthorised | (err u5000) | | +| xverse-member6 | err-unauthorised | (err u5000) | | +| xverse-member7 | err-unauthorised | (err u5000) | | +| xverse-member8 | err-unauthorised | (err u5000) | | +| xverse-member9 | err-unauthorised | (err u5000) | | +| pox-pools-1-cycle-v2 | err-no-stacker-info | (err u501) | | +| pox-pools-1-cycle-v2 | err-no-user-info | (err u502) | | +| pox-fast-pool-v2 | err-decrease-forbidden | (err u503) | | +| pox-pools-1-cycle-v2 | err-decrease-forbidden | (err u503) | | +| pox-fast-pool-v2 | err-pox-address-deactivated | (err u504) | | +| token-wlqstx | err-mint-failed | (err u6002) | | +| token-wlqstx | err-burn-failed | (err u6003) | | +| token-wlqstx | err-not-supported | (err u6004) | | +| pox-fast-pool-v2 | err-already-stacking | (err u603) | | +| pox-pools-1-cycle-v2 | err-already-stacking | (err u603) | | +| pox-fast-pool-v2 | err-stacking-permission-denied | (err u609) | | +| pox-pools-1-cycle-v2 | err-stacking-permission-denied | (err u609) | | +| lqstx-mint-endpoint-v1-02 | err-paused | (err u7001) | | +| lqstx-mint-endpoint-v1-02 | err-request-pending | (err u7006) | | +| lqstx-mint-endpoint-v1-02 | err-request-finalized-or-revoked | (err u7007) | | +| lqstx-mint-endpoint-v1-02 | err-not-whitelisted | (err u7008) | | +| token-vesting | err-caller-not-recipient | (err u9000) | | +| token-vesting | err-unknown-vesting-id | (err u9001) | | +| token-vesting | err-event-not-vested | (err u9002) | | +| token-vesting | err-event-already-claimed | (err u9003) | | +| token-vesting | err-recipient-exists | (err u9004) | | + + +## References diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index c6ef3d6..be067fe 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -2,7 +2,7 @@ ;; SPDX-License-Identifier: BUSL-1.1 ;; -;; lqstx-mint-endpoint-v1-01 +;; lqstx-mint-endpoint-v1-02 ;; ;; __IF_MAINNET__ @@ -10,11 +10,11 @@ ;; (use-trait sip-010-trait .sip-010-trait.sip-010-trait) ;; __ENDIF__ -(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 err-unauthorised (err u3000)) +(define-constant err-paused (err u7001)) +(define-constant err-request-pending (err u7006)) +(define-constant err-request-finalized-or-revoked (err u7007)) +(define-constant err-not-whitelisted (err u7008)) (define-constant PENDING 0x00) (define-constant FINALIZED 0x01) diff --git a/package.json b/package.json index 49952bf..b392cd5 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "multisig-analyse": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/analyse-multisig-deployment-plan.ts", "get-keys": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/get-secret-pubkeys.ts", "generate-secret": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/generate-secret.ts", + "error-codes": "node --no-warnings=ExperimentalWarning --loader ts-node/esm --import=./scripts/logErrors.js ./scripts/error-codes.ts", "replace:mainnet": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/replace-mainnet-address.ts", "replace:testnet": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/replace-testnet-address.ts", "setup:clarity": "./scripts/clarinet_manager.sh clean && ./scripts/clarinet_manager.sh install", diff --git a/scripts/error-codes.ts b/scripts/error-codes.ts new file mode 100644 index 0000000..9a9d041 --- /dev/null +++ b/scripts/error-codes.ts @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: BUSL-1.1 +import { initSimnet } from '@hirosystems/clarinet-sdk'; +import { readFileSync, writeFileSync } from 'fs'; +const readmeFile = './README.md'; +const manifestFile = './Clarinet.toml'; + +const constantErrRegex = /^\s*\(define-constant\s+(err-.+?)\s+(\(.+?\))\s*\)(.*?)$/gm; +const errorCodeRegex = /u([0-9]+)/; +const commentRegex = /;;\s*(.+)/; +const readmeErrorsDelineator = ''; + +const tableHeader = ['Contract', 'Constant', 'Value', 'Description']; + +const simnet = await initSimnet(manifestFile); + +export function isTestContract(contractName: string) { + return contractName.indexOf('mock') >= 0; +} + +function padTableCell(content: string, length: number) { + const repeat = length - content.length + 1; + return repeat > 0 ? ' ' + content + ' '.repeat(repeat) : ' '; +} + +function createErrorsTable() { + const errorsSeenCount: { [key: string]: { lastConstantName: string; count: number } } = {}; + let readme = readFileSync(readmeFile).toString(); + const errorTable: Array> = []; + const longestColumnCells = tableHeader.map(v => v.length); + + const compareReadme = process.env.EXTRACT_CHECK && readme; + + for (const [contractId, abi] of simnet.getContractsInterfaces()) { + if (isTestContract(contractId)) continue; + console.log(abi); + const source = simnet.getContractSource(contractId); + if (!source) continue; + const errorConstants = source.matchAll(constantErrRegex); + for (const [, errorConstant, errorValue, errorComment] of errorConstants) { + const errorDescription = errorComment?.match(commentRegex)?.[1] || ''; // || '_None_'; + if (!errorValue.match(errorCodeRegex)) + console.error(`Constant '${errorConstant}' error value is not in form of (err uint)`); + if (!errorsSeenCount[errorValue]) + errorsSeenCount[errorValue] = { lastConstantName: errorConstant, count: 1 }; + else if (errorsSeenCount[errorValue].lastConstantName !== errorConstant) { + errorsSeenCount[errorValue].lastConstantName = errorConstant; + ++errorsSeenCount[errorValue].count; + } + const row = [contractId.split('.')[1], errorConstant, errorValue, errorDescription]; + row.map((content, index) => { + if (content.length > longestColumnCells[index]) longestColumnCells[index] = content.length; + }); + errorTable.push(row); + } + } + + const nonUniqueErrors = Object.entries(errorsSeenCount).filter(([, value]) => value.count > 1); + if (nonUniqueErrors.length > 0) console.log(nonUniqueErrors); + + errorTable.sort((a, b) => (a[2] === b[2] ? (a[0] > b[0] ? 1 : -1) : a[2] > b[2] ? 1 : -1)); // string sort + + let errors = + '|' + + tableHeader + .map((content, index) => padTableCell(content, longestColumnCells[index])) + .join('|') + + '|\n'; + errors += '|' + longestColumnCells.map(length => '-'.repeat(length + 2)).join('|') + '|\n'; + errors += errorTable.reduce( + (accumulator, row) => + accumulator + + '|' + + row.map((content, index) => padTableCell(content, longestColumnCells[index])).join('|') + + '|\n', + '' + ); + + const split = readme.split(readmeErrorsDelineator); + readme = `${split[0]}${readmeErrorsDelineator}\n${errors}${readmeErrorsDelineator}${split[2]}`; + + if (compareReadme && compareReadme !== readme) { + throw new Error( + 'Generated readme is not equal to readme in current commit (error table mismatch)' + ); + } + + writeFileSync(readmeFile, readme); + console.log(`Error table written to ${readmeFile}`); +} + +console.log('start'); +createErrorsTable(); diff --git a/scripts/logErrors.js b/scripts/logErrors.js new file mode 100644 index 0000000..191a234 --- /dev/null +++ b/scripts/logErrors.js @@ -0,0 +1,5 @@ +import { setUncaughtExceptionCaptureCallback } from 'node:process'; +setUncaughtExceptionCaptureCallback(err => { + console.error(err); + process.exit(1); +}); diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index 470e294..b003e53 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -105,7 +105,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(1006)); + expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay @@ -114,7 +114,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), ]); expect(responses[0].result).toBeOk(Cl.bool(true)); - expect(responses[1].result).toBeErr(Cl.uint(1007)); + expect(responses[1].result).toBeErr(Cl.uint(7007)); }); it('can revoke mint', () => { @@ -126,7 +126,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], bot), tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), ]); - expect(responses[0].result).toBeErr(Cl.uint(1000)); + expect(responses[0].result).toBeErr(Cl.uint(3000)); expect(responses[1].result).toBeOk(Cl.bool(true)); goToNextCycle(); @@ -134,7 +134,7 @@ describe(contracts.endpoint, () => { responses = simnet.mineBlock([ tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), ]); - expect(responses[0].result).toBeErr(Cl.uint(1007)); + expect(responses[0].result).toBeErr(Cl.uint(7007)); }); it('can request burn', () => { @@ -181,7 +181,7 @@ describe(contracts.endpoint, () => { expect(responses[0].result).toBeOk(Cl.uint(1e6)); expect(responses[1].result).toBeOk(Cl.uint(mintAmount)); expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(1007)); + expect(responses[3].result).toBeErr(Cl.uint(7007)); }); it('can revoke burn', () => { @@ -207,9 +207,9 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeOk(Cl.uint(1e6)); - expect(responses[1].result).toBeErr(Cl.uint(1000)); + expect(responses[1].result).toBeErr(Cl.uint(3000)); expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(1007)); + expect(responses[3].result).toBeErr(Cl.uint(7007)); }); it('can interact with strategies', () => { @@ -248,7 +248,7 @@ describe(contracts.endpoint, () => { manager ), ]); - expect(responses[0].result).toBeErr(Cl.uint(1006)); // request pending + expect(responses[0].result).toBeErr(Cl.uint(7006)); // request pending expect(responses[1].result).toBeErr(Cl.uint(3000)); // not authorized responses[2].events.map((e: any) => console.log(e)); expect(responses[2].result).toBeOk(Cl.uint(mintAmount)); // mintAmount stx transferred, mintAmount - 1 stx locked @@ -277,12 +277,12 @@ describe(contracts.endpoint, () => { Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); expect(responses[2].result).toBeErr(Cl.uint(1)); // not enough funds - expect(responses[3].result).toBeErr(Cl.uint(1006)); // request pending + expect(responses[3].result).toBeErr(Cl.uint(7006)); // request pending expect(responses[4].result).toBeErr(Cl.uint(3000)); // not authorized expect(responses[5].result).toBeOk(Cl.uint(1e6)); // refund 1 stx expect(responses[6].result).toBeOk(Cl.uint(0)); // refund 0 stx expect(responses[7].result).toBeOk(Cl.uint(mintAmount)); // rebase mintAmount stx - expect(responses[8].result).toBeErr(Cl.uint(1006)); // request pending + expect(responses[8].result).toBeErr(Cl.uint(7006)); // request pending // refund remaining stx after unlock goToNextCycle(); @@ -404,7 +404,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); // go to the next cycle const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(1006)); + expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 8618a19..84d14d2 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -117,7 +117,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(1006)); + expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay); @@ -126,7 +126,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), ]); expect(responses[0].result).toBeOk(Cl.bool(true)); - expect(responses[1].result).toBeErr(Cl.uint(1007)); + expect(responses[1].result).toBeErr(Cl.uint(7007)); }); it('can revoke mint', () => { @@ -138,7 +138,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], bot), tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), ]); - expect(responses[0].result).toBeErr(Cl.uint(1000)); + expect(responses[0].result).toBeErr(Cl.uint(3000)); expect(responses[1].result).toBeOk(Cl.bool(true)); goToNextCycle(); @@ -147,7 +147,7 @@ describe(contracts.endpoint, () => { responses = simnet.mineBlock([ tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), ]); - expect(responses[0].result).toBeErr(Cl.uint(1007)); + expect(responses[0].result).toBeErr(Cl.uint(7007)); }); it('can request burn', () => { @@ -205,7 +205,7 @@ describe(contracts.endpoint, () => { expect(responses[0].result).toBeOk(Cl.uint(100e6)); expect(responses[1].result).toBeOk(Cl.uint(100e6)); expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(1007)); + expect(responses[3].result).toBeErr(Cl.uint(7007)); }); it('can revoke burn', () => { @@ -237,9 +237,9 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeOk(Cl.uint(100e6)); - expect(responses[1].result).toBeErr(Cl.uint(1000)); + expect(responses[1].result).toBeErr(Cl.uint(3000)); expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(1007)); + expect(responses[3].result).toBeErr(Cl.uint(7007)); }); it('can request burn and finalized immediately', () => { @@ -274,7 +274,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.uint(100e6)], bot), tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.uint(100e6)], manager), ]); - expect(responses[0].result).toBeErr(Cl.uint(1006)); + expect(responses[0].result).toBeErr(Cl.uint(7006)); expect(responses[1].result).toBeErr(Cl.uint(1000)); expect(responses[2].result).toBeOk(Cl.uint(100e6)); @@ -295,7 +295,7 @@ describe(contracts.endpoint, () => { expect(responses[1].result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); - expect(responses[2].result).toBeErr(Cl.uint(1006)); + expect(responses[2].result).toBeErr(Cl.uint(7006)); expect(responses[3].result).toBeErr(Cl.uint(1000)); expect(responses[4].result).toBeOk(Cl.uint(100e6)); expect(responses[5].result).toBeErr(Cl.uint(1)); @@ -311,7 +311,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(1006)); + expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay); From bbf4041ff5cc21348a941725a700e7d69bc8aab2 Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 15:22:03 +0100 Subject: [PATCH 11/32] chore: fix error code table --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c599a1..939196d 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ are in the form `(err uint)` and they are unique across all contracts. | lisa-dao | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint-v1-01 | err-unauthorised | (err u1000) | | +| lqstx-mint-registry | err-unauthorised | (err u1000) | | | lqstx-vault | err-unauthorised | (err u1000) | | | operators | err-unauthorised | (err u1000) | | | token-vesting | err-unauthorised | (err u1000) | | @@ -60,7 +61,6 @@ are in the form `(err uint)` and they are unique across all contracts. | lisa-rebase | err-unauthorised | (err u3000) | | | lisa-rebase-v1-02 | err-unauthorised | (err u3000) | | | lqstx-mint-endpoint-v1-02 | err-unauthorised | (err u3000) | | -| lqstx-mint-registry | err-unauthorised | (err u3000) | | | public-pools-strategy-manager | err-unauthorised | (err u3000) | | | token-lisa | err-unauthorised | (err u3000) | | | token-lqstx | err-unauthorised | (err u3000) | | From 44fa4a2a5daa383822062c6991ebd5c0c77f287c Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 15:42:36 +0100 Subject: [PATCH 12/32] chore: add unit test --- scripts/error-codes.ts | 89 +------------------------------------- scripts/lib/error-codes.ts | 87 +++++++++++++++++++++++++++++++++++++ tests/errors.test.ts | 9 ++++ 3 files changed, 98 insertions(+), 87 deletions(-) create mode 100644 scripts/lib/error-codes.ts create mode 100644 tests/errors.test.ts diff --git a/scripts/error-codes.ts b/scripts/error-codes.ts index 9a9d041..1dfdc55 100644 --- a/scripts/error-codes.ts +++ b/scripts/error-codes.ts @@ -1,92 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import { initSimnet } from '@hirosystems/clarinet-sdk'; -import { readFileSync, writeFileSync } from 'fs'; -const readmeFile = './README.md'; +import { createErrorsTable } from './lib/error-codes.ts'; const manifestFile = './Clarinet.toml'; - -const constantErrRegex = /^\s*\(define-constant\s+(err-.+?)\s+(\(.+?\))\s*\)(.*?)$/gm; -const errorCodeRegex = /u([0-9]+)/; -const commentRegex = /;;\s*(.+)/; -const readmeErrorsDelineator = ''; - -const tableHeader = ['Contract', 'Constant', 'Value', 'Description']; - const simnet = await initSimnet(manifestFile); -export function isTestContract(contractName: string) { - return contractName.indexOf('mock') >= 0; -} - -function padTableCell(content: string, length: number) { - const repeat = length - content.length + 1; - return repeat > 0 ? ' ' + content + ' '.repeat(repeat) : ' '; -} - -function createErrorsTable() { - const errorsSeenCount: { [key: string]: { lastConstantName: string; count: number } } = {}; - let readme = readFileSync(readmeFile).toString(); - const errorTable: Array> = []; - const longestColumnCells = tableHeader.map(v => v.length); - - const compareReadme = process.env.EXTRACT_CHECK && readme; - - for (const [contractId, abi] of simnet.getContractsInterfaces()) { - if (isTestContract(contractId)) continue; - console.log(abi); - const source = simnet.getContractSource(contractId); - if (!source) continue; - const errorConstants = source.matchAll(constantErrRegex); - for (const [, errorConstant, errorValue, errorComment] of errorConstants) { - const errorDescription = errorComment?.match(commentRegex)?.[1] || ''; // || '_None_'; - if (!errorValue.match(errorCodeRegex)) - console.error(`Constant '${errorConstant}' error value is not in form of (err uint)`); - if (!errorsSeenCount[errorValue]) - errorsSeenCount[errorValue] = { lastConstantName: errorConstant, count: 1 }; - else if (errorsSeenCount[errorValue].lastConstantName !== errorConstant) { - errorsSeenCount[errorValue].lastConstantName = errorConstant; - ++errorsSeenCount[errorValue].count; - } - const row = [contractId.split('.')[1], errorConstant, errorValue, errorDescription]; - row.map((content, index) => { - if (content.length > longestColumnCells[index]) longestColumnCells[index] = content.length; - }); - errorTable.push(row); - } - } - - const nonUniqueErrors = Object.entries(errorsSeenCount).filter(([, value]) => value.count > 1); - if (nonUniqueErrors.length > 0) console.log(nonUniqueErrors); - - errorTable.sort((a, b) => (a[2] === b[2] ? (a[0] > b[0] ? 1 : -1) : a[2] > b[2] ? 1 : -1)); // string sort - - let errors = - '|' + - tableHeader - .map((content, index) => padTableCell(content, longestColumnCells[index])) - .join('|') + - '|\n'; - errors += '|' + longestColumnCells.map(length => '-'.repeat(length + 2)).join('|') + '|\n'; - errors += errorTable.reduce( - (accumulator, row) => - accumulator + - '|' + - row.map((content, index) => padTableCell(content, longestColumnCells[index])).join('|') + - '|\n', - '' - ); - - const split = readme.split(readmeErrorsDelineator); - readme = `${split[0]}${readmeErrorsDelineator}\n${errors}${readmeErrorsDelineator}${split[2]}`; - - if (compareReadme && compareReadme !== readme) { - throw new Error( - 'Generated readme is not equal to readme in current commit (error table mismatch)' - ); - } - - writeFileSync(readmeFile, readme); - console.log(`Error table written to ${readmeFile}`); -} - -console.log('start'); -createErrorsTable(); +createErrorsTable(simnet, false); diff --git a/scripts/lib/error-codes.ts b/scripts/lib/error-codes.ts new file mode 100644 index 0000000..04e9adf --- /dev/null +++ b/scripts/lib/error-codes.ts @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BUSL-1.1 + +import { Simnet } from '@hirosystems/clarinet-sdk'; +import { readFileSync, writeFileSync } from 'fs'; +const readmeFile = './README.md'; + +const constantErrRegex = /^\s*\(define-constant\s+(err-.+?)\s+(\(.+?\))\s*\)(.*?)$/gm; +const errorCodeRegex = /u([0-9]+)/; +const commentRegex = /;;\s*(.+)/; +const readmeErrorsDelineator = ''; + +const tableHeader = ['Contract', 'Constant', 'Value', 'Description']; + +export function isTestContract(contractName: string) { + return contractName.indexOf('mock') >= 0; +} + +function padTableCell(content: string, length: number) { + const repeat = length - content.length + 1; + return repeat > 0 ? ' ' + content + ' '.repeat(repeat) : ' '; +} + +export function createErrorsTable(simnet: Simnet, extractCheck: boolean) { + const errorsSeenCount: { [key: string]: { lastConstantName: string; count: number } } = {}; + let readme = readFileSync(readmeFile).toString(); + const errorTable: Array> = []; + const longestColumnCells = tableHeader.map(v => v.length); + + const compareReadme = extractCheck && readme; + + for (const [contractId, abi] of simnet.getContractsInterfaces()) { + if (isTestContract(contractId)) continue; + console.log(abi); + const source = simnet.getContractSource(contractId); + if (!source) continue; + const errorConstants = source.matchAll(constantErrRegex); + for (const [, errorConstant, errorValue, errorComment] of errorConstants) { + const errorDescription = errorComment?.match(commentRegex)?.[1] || ''; // || '_None_'; + if (!errorValue.match(errorCodeRegex)) + console.error(`Constant '${errorConstant}' error value is not in form of (err uint)`); + if (!errorsSeenCount[errorValue]) + errorsSeenCount[errorValue] = { lastConstantName: errorConstant, count: 1 }; + else if (errorsSeenCount[errorValue].lastConstantName !== errorConstant) { + errorsSeenCount[errorValue].lastConstantName = errorConstant; + ++errorsSeenCount[errorValue].count; + } + const row = [contractId.split('.')[1], errorConstant, errorValue, errorDescription]; + row.map((content, index) => { + if (content.length > longestColumnCells[index]) longestColumnCells[index] = content.length; + }); + errorTable.push(row); + } + } + + const nonUniqueErrors = Object.entries(errorsSeenCount).filter(([, value]) => value.count > 1); + if (nonUniqueErrors.length > 0) console.log(nonUniqueErrors); + + errorTable.sort((a, b) => (a[2] === b[2] ? (a[0] > b[0] ? 1 : -1) : a[2] > b[2] ? 1 : -1)); // string sort + + let errors = + '|' + + tableHeader + .map((content, index) => padTableCell(content, longestColumnCells[index])) + .join('|') + + '|\n'; + errors += '|' + longestColumnCells.map(length => '-'.repeat(length + 2)).join('|') + '|\n'; + errors += errorTable.reduce( + (accumulator, row) => + accumulator + + '|' + + row.map((content, index) => padTableCell(content, longestColumnCells[index])).join('|') + + '|\n', + '' + ); + + const split = readme.split(readmeErrorsDelineator); + readme = `${split[0]}${readmeErrorsDelineator}\n${errors}${readmeErrorsDelineator}${split[2]}`; + + if (compareReadme && compareReadme !== readme) { + throw new Error( + 'Generated readme is not equal to readme in current commit (error table mismatch)' + ); + } + + writeFileSync(readmeFile, readme); + console.log(`Error table written to ${readmeFile}`); +} diff --git a/tests/errors.test.ts b/tests/errors.test.ts new file mode 100644 index 0000000..3bdbac2 --- /dev/null +++ b/tests/errors.test.ts @@ -0,0 +1,9 @@ +import { describe, it } from 'vitest'; +import { createErrorsTable } from '../scripts/lib/error-codes.ts'; + +describe('readme', () => { + it('should have the correct error code table', () => { + createErrorsTable(simnet, true); + // should not throw an error + }); +}); From 582ef20cb4569cbf0bbfc77b6ecb3279bc2ba5a9 Mon Sep 17 00:00:00 2001 From: friedger Date: Wed, 20 Mar 2024 15:42:56 +0100 Subject: [PATCH 13/32] chore: add license --- tests/errors.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/errors.test.ts b/tests/errors.test.ts index 3bdbac2..aa666ae 100644 --- a/tests/errors.test.ts +++ b/tests/errors.test.ts @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: BUSL-1.1 + import { describe, it } from 'vitest'; import { createErrorsTable } from '../scripts/lib/error-codes.ts'; From 9de9f1a454252527be05522c5b52bf74a9a9e7fc Mon Sep 17 00:00:00 2001 From: friedger Date: Thu, 21 Mar 2024 01:36:24 +0100 Subject: [PATCH 14/32] feat: add nft for mint and burn requests --- Clarinet.toml | 14 ++ README.md | 17 ++- contracts/aux/li-stx-burn-nft.clar | 136 ++++++++++++++++++ contracts/aux/li-stx-mint-nft.clar | 136 ++++++++++++++++++ contracts/extensions/lqstx-mint-endpoint.clar | 6 + deployments/default.simnet-plan.yaml | 26 +++- scripts/lib/error-codes.ts | 3 +- tests/lqstx-mint-endpoint.test.ts | 5 +- 8 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 contracts/aux/li-stx-burn-nft.clar create mode 100644 contracts/aux/li-stx-mint-nft.clar diff --git a/Clarinet.toml b/Clarinet.toml index f57bae7..b21ee74 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -15,6 +15,12 @@ contract_id = "SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2" [[project.requirements]] contract_id = "SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard" +[[project.requirements]] +contract_id = "SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait" + +[[project.requirements]] +contract_id = "SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait" + [contracts.lisa-dao] path = "contracts/lisa-dao.clar" epoch = 2.4 @@ -191,6 +197,14 @@ epoch = 2.4 path = "contracts/aux/lqstx-mint-registry.clar" epoch = 2.4 +[contracts.li-stx-mint-nft] +path = "contracts/aux/li-stx-mint-nft.clar" +epoch = 2.4 + +[contracts.li-stx-burn-nft] +path = "contracts/aux/li-stx-burn-nft.clar" +epoch = 2.4 + [contracts.token-lqstx] path = "contracts/token-lqstx.clar" epoch = 2.4 diff --git a/README.md b/README.md index 939196d..e3bc89e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ are in the form `(err uint)` and they are unique across all contracts. | Pool members | 5XXX | Errors related to stacking pool members. | | Wrapped token | 6XXX | Errors coming directly from the wrapped token. | | Mint Endpoint | 7XXX | Errors coming directly from the mint endpoint. | +| NFTs | 8XXX | Errors coming directly from the NFTs. | | Vesting | 9XXX | Errors coming directly from vesting. | | Pools | 4XX/5XX/6XX | Errors coming public stacking pools. | | Assets | 1/2/3/4 | Errors coming for native Clarity assets. | @@ -29,8 +30,9 @@ are in the form `(err uint)` and they are unique across all contracts. ### Error table + | Contract | Constant | Value | Description | -|-------------------------------|----------------------------------|-------------|-------------| +| ----------------------------- | -------------------------------- | ----------- | ----------- | | lisa-dao | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint-v1-01 | err-unauthorised | (err u1000) | | @@ -58,6 +60,8 @@ are in the form `(err uint)` and they are unique across all contracts. | lqstx-mint-registry | err-unknown-request-id | (err u1008) | | | public-pools-strategy | err-not-vault-caller | (err u2000) | | | public-pools-strategy | err-invalid-payload | (err u2001) | | +| li-stx-burn-nft | err-unauthorised | (err u3000) | | +| li-stx-mint-nft | err-unauthorised | (err u3000) | | | lisa-rebase | err-unauthorised | (err u3000) | | | lisa-rebase-v1-02 | err-unauthorised | (err u3000) | | | lqstx-mint-endpoint-v1-02 | err-unauthorised | (err u3000) | | @@ -113,11 +117,22 @@ are in the form `(err uint)` and they are unique across all contracts. | lqstx-mint-endpoint-v1-02 | err-request-pending | (err u7006) | | | lqstx-mint-endpoint-v1-02 | err-request-finalized-or-revoked | (err u7007) | | | lqstx-mint-endpoint-v1-02 | err-not-whitelisted | (err u7008) | | +| li-stx-mint-nft | err-not-authorized | (err u8000) | | +| li-stx-mint-nft | err-listing | (err u8001) | | +| li-stx-mint-nft | err-wrong-commission | (err u8002) | | +| li-stx-mint-nft | err-not-found | (err u8003) | | +| li-stx-mint-nft | err-metadata-frozen | (err u8004) | | +| li-stx-burn-nft | err-not-authorized | (err u8100) | | +| li-stx-burn-nft | err-listing | (err u8101) | | +| li-stx-burn-nft | err-wrong-commission | (err u8102) | | +| li-stx-burn-nft | err-not-found | (err u8103) | | +| li-stx-burn-nft | err-metadata-frozen | (err u8104) | | | token-vesting | err-caller-not-recipient | (err u9000) | | | token-vesting | err-unknown-vesting-id | (err u9001) | | | token-vesting | err-event-not-vested | (err u9002) | | | token-vesting | err-event-already-claimed | (err u9003) | | | token-vesting | err-recipient-exists | (err u9004) | | + ## References diff --git a/contracts/aux/li-stx-burn-nft.clar b/contracts/aux/li-stx-burn-nft.clar new file mode 100644 index 0000000..f0fe25f --- /dev/null +++ b/contracts/aux/li-stx-burn-nft.clar @@ -0,0 +1,136 @@ +;; li-stx-burn +;; contractType: public + +(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait) + +(define-non-fungible-token li-stx-burn uint) + +;; Constants +(define-constant err-not-authorized (err u8100)) +(define-constant err-listing (err u8101)) +(define-constant err-wrong-commission (err u8102)) +(define-constant err-not-found (err u8103)) +(define-constant err-metadata-frozen (err u8104)) + +(define-constant err-unauthorised (err u3000)) + +(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)) +) + +;; Internal variables +(define-data-var last-id uint u0) +(define-data-var ipfs-root (string-ascii 80) "") +(define-data-var metadata-frozen bool false) + +(define-public (mint (id uint) (amount uint)) + (let ((current-balance (get-balance tx-sender))) + (try! (is-dao-or-extension)) + (var-set last-id id) + (map-set token-count tx-sender (+ current-balance u1)) + (nft-mint? li-stx-burn id tx-sender))) + +(define-public (burn (token-id uint)) + (let ((owner (unwrap! (nft-get-owner? li-stx-burn token-id) err-not-found)) + (current-balance (get-balance owner))) + (try! (is-dao-or-extension)) + (asserts! (is-none (map-get? market token-id)) err-listing) + (try! (nft-burn? li-stx-burn token-id owner)) + (map-set token-count owner (- current-balance u1)) + (ok true))) + +(define-private (is-owner (token-id uint) (user principal)) + (is-eq user (unwrap! (nft-get-owner? li-stx-burn token-id) false))) + +;; governance calls + +(define-public (set-base-uri (new-base-uri (string-ascii 80))) + (begin + (try! (is-dao-or-extension)) + (asserts! (not (var-get metadata-frozen)) err-metadata-frozen) + (print { notification: "token-metadata-update", payload: { token-class: "nft", contract-id: (as-contract tx-sender) }}) + (var-set ipfs-root new-base-uri) + (ok true))) + +(define-public (freeze-metadata) + (begin + (try! (is-dao-or-extension)) + (var-set metadata-frozen true) + (ok true))) + +;; Non-custodial SIP-009 transfer function +(define-public (transfer (id uint) (sender principal) (recipient principal)) + (begin + (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) err-not-authorized) + (asserts! (is-none (map-get? market id)) err-listing) + (trnsfr id sender recipient))) + +;; read-only functions +(define-read-only (get-owner (token-id uint)) + (ok (nft-get-owner? li-stx-burn token-id))) + +(define-read-only (get-last-token-id) + (ok (- (var-get last-id) u1))) + +(define-read-only (get-token-uri (token-id uint)) + (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) + +;; Non-custodial marketplace extras +(use-trait commission-trait 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait.commission) + +(define-map token-count principal uint) +(define-map market uint {price: uint, commission: principal, royalty: uint}) + +(define-read-only (get-balance (account principal)) + (default-to u0 + (map-get? token-count account))) + +(define-private (trnsfr (id uint) (sender principal) (recipient principal)) + (match (nft-transfer? li-stx-burn id sender recipient) + success + (let + ((sender-balance (get-balance sender)) + (recipient-balance (get-balance recipient))) + (map-set token-count + sender + (- sender-balance u1)) + (map-set token-count + recipient + (+ recipient-balance u1)) + (ok success)) + error (err error))) + +(define-private (is-sender-owner (id uint)) + (let ((owner (unwrap! (nft-get-owner? li-stx-burn id) false))) + (or (is-eq tx-sender owner) (is-eq contract-caller owner)))) + +(define-read-only (get-listing-in-ustx (id uint)) + (map-get? market id)) + +(define-public (list-in-ustx (id uint) (price uint) (comm-trait )) + (let ((listing {price: price, commission: (contract-of comm-trait), royalty: u0})) + (asserts! (is-sender-owner id) err-not-authorized) + (map-set market id listing) + (print (merge listing {a: "list-in-ustx", id: id})) + (ok true))) + +(define-public (unlist-in-ustx (id uint)) + (begin + (asserts! (is-sender-owner id) err-not-authorized) + (map-delete market id) + (print {a: "unlist-in-ustx", id: id}) + (ok true))) + +(define-public (buy-in-ustx (id uint) (comm-trait )) + (let ((owner (unwrap! (nft-get-owner? li-stx-burn id) err-not-found)) + (listing (unwrap! (map-get? market id) err-listing)) + (price (get price listing)) + (royalty (get royalty listing))) + (asserts! (is-eq (contract-of comm-trait) (get commission listing)) err-wrong-commission) + (try! (stx-transfer? price tx-sender owner)) + (try! (contract-call? comm-trait pay id price)) + (try! (trnsfr id owner tx-sender)) + (map-delete market id) + (print {a: "buy-in-ustx", id: id}) + (ok true))) + diff --git a/contracts/aux/li-stx-mint-nft.clar b/contracts/aux/li-stx-mint-nft.clar new file mode 100644 index 0000000..534f2ad --- /dev/null +++ b/contracts/aux/li-stx-mint-nft.clar @@ -0,0 +1,136 @@ +;; li-stx-mint +;; contractType: public + +(impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait) + +(define-non-fungible-token li-stx-mint uint) + +;; Constants +(define-constant err-not-authorized (err u8000)) +(define-constant err-listing (err u8001)) +(define-constant err-wrong-commission (err u8002)) +(define-constant err-not-found (err u8003)) +(define-constant err-metadata-frozen (err u8004)) + +(define-constant err-unauthorised (err u3000)) + +(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)) +) + +;; Internal variables +(define-data-var last-id uint u0) +(define-data-var ipfs-root (string-ascii 80) "") +(define-data-var metadata-frozen bool false) + +(define-public (mint (id uint) (amount uint)) + (let ((current-balance (get-balance tx-sender))) + (try! (is-dao-or-extension)) + (var-set last-id id) + (map-set token-count tx-sender (+ current-balance u1)) + (nft-mint? li-stx-mint id tx-sender))) + +(define-public (burn (token-id uint)) + (let ((owner (unwrap! (nft-get-owner? li-stx-mint token-id) err-not-found)) + (current-balance (get-balance owner))) + (try! (is-dao-or-extension)) + (asserts! (is-none (map-get? market token-id)) err-listing) + (try! (nft-burn? li-stx-mint token-id owner)) + (map-set token-count owner (- current-balance u1)) + (ok true))) + +(define-private (is-owner (token-id uint) (user principal)) + (is-eq user (unwrap! (nft-get-owner? li-stx-mint token-id) false))) + +;; governance calls + +(define-public (set-base-uri (new-base-uri (string-ascii 80))) + (begin + (try! (is-dao-or-extension)) + (asserts! (not (var-get metadata-frozen)) err-metadata-frozen) + (print { notification: "token-metadata-update", payload: { token-class: "nft", contract-id: (as-contract tx-sender) }}) + (var-set ipfs-root new-base-uri) + (ok true))) + +(define-public (freeze-metadata) + (begin + (try! (is-dao-or-extension)) + (var-set metadata-frozen true) + (ok true))) + +;; Non-custodial SIP-009 transfer function +(define-public (transfer (id uint) (sender principal) (recipient principal)) + (begin + (asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) err-not-authorized) + (asserts! (is-none (map-get? market id)) err-listing) + (trnsfr id sender recipient))) + +;; read-only functions +(define-read-only (get-owner (token-id uint)) + (ok (nft-get-owner? li-stx-mint token-id))) + +(define-read-only (get-last-token-id) + (ok (- (var-get last-id) u1))) + +(define-read-only (get-token-uri (token-id uint)) + (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) + +;; Non-custodial marketplace extras +(use-trait commission-trait 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait.commission) + +(define-map token-count principal uint) +(define-map market uint {price: uint, commission: principal, royalty: uint}) + +(define-read-only (get-balance (account principal)) + (default-to u0 + (map-get? token-count account))) + +(define-private (trnsfr (id uint) (sender principal) (recipient principal)) + (match (nft-transfer? li-stx-mint id sender recipient) + success + (let + ((sender-balance (get-balance sender)) + (recipient-balance (get-balance recipient))) + (map-set token-count + sender + (- sender-balance u1)) + (map-set token-count + recipient + (+ recipient-balance u1)) + (ok success)) + error (err error))) + +(define-private (is-sender-owner (id uint)) + (let ((owner (unwrap! (nft-get-owner? li-stx-mint id) false))) + (or (is-eq tx-sender owner) (is-eq contract-caller owner)))) + +(define-read-only (get-listing-in-ustx (id uint)) + (map-get? market id)) + +(define-public (list-in-ustx (id uint) (price uint) (comm-trait )) + (let ((listing {price: price, commission: (contract-of comm-trait), royalty: u0})) + (asserts! (is-sender-owner id) err-not-authorized) + (map-set market id listing) + (print (merge listing {a: "list-in-ustx", id: id})) + (ok true))) + +(define-public (unlist-in-ustx (id uint)) + (begin + (asserts! (is-sender-owner id) err-not-authorized) + (map-delete market id) + (print {a: "unlist-in-ustx", id: id}) + (ok true))) + +(define-public (buy-in-ustx (id uint) (comm-trait )) + (let ((owner (unwrap! (nft-get-owner? li-stx-mint id) err-not-found)) + (listing (unwrap! (map-get? market id) err-listing)) + (price (get price listing)) + (royalty (get royalty listing))) + (asserts! (is-eq (contract-of comm-trait) (get commission listing)) err-wrong-commission) + (try! (stx-transfer? price tx-sender owner)) + (try! (contract-call? comm-trait pay id price)) + (try! (trnsfr id owner tx-sender)) + (map-delete market id) + (print {a: "buy-in-ustx", id: id}) + (ok true))) + diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index be067fe..f906ab9 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -129,6 +129,7 @@ (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)))) + (try! (contract-call? .li-stx-mint-nft mint request-id amount)) (print { type: "mint-request", id: request-id, details: request-details }) (ok request-id))) @@ -144,6 +145,7 @@ (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))) + (try! (contract-call? .li-stx-mint-nft burn request-id)) (ok true))) (define-public (revoke-burn (request-id uint)) @@ -160,6 +162,7 @@ (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))) + (try! (contract-call? .li-stx-burn-nft burn request-id)) (ok true))) ;; governance calls @@ -207,6 +210,7 @@ (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))) + (try! (contract-call? .li-stx-mint-nft burn request-id)) (ok true))) (define-public (finalize-mint-many (request-ids (list 1000 uint))) @@ -224,6 +228,7 @@ (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)))) + (try! (contract-call? .li-stx-burn-nft mint request-id amount)) (print { type: "burn-request", id: request-id, details: request-details }) (ok { request-id: request-id, status: PENDING }))) @@ -240,6 +245,7 @@ (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)))) + (try! (contract-call? .li-stx-burn-nft burn request-id)) (ok true))) (define-public (finalize-burn-many (request-ids (list 1000 uint))) diff --git a/deployments/default.simnet-plan.yaml b/deployments/default.simnet-plan.yaml index 9dcdf2d..1311056 100644 --- a/deployments/default.simnet-plan.yaml +++ b/deployments/default.simnet-plan.yaml @@ -49,6 +49,16 @@ plan: batches: - id: 0 transactions: + - emulated-contract-publish: + contract-name: nft-trait + emulated-sender: SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9 + path: "./.cache/requirements/SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.clar" + clarity-version: 1 + - emulated-contract-publish: + contract-name: commission-trait + emulated-sender: SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335 + path: "./.cache/requirements/SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait.clar" + clarity-version: 1 - emulated-contract-publish: contract-name: sip-010-trait-ft-standard emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE @@ -295,6 +305,16 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/boot.clar clarity-version: 2 + - emulated-contract-publish: + contract-name: li-stx-burn-nft + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/aux/li-stx-burn-nft.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: li-stx-mint-nft + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/aux/li-stx-mint-nft.clar + clarity-version: 2 - emulated-contract-publish: contract-name: lisa-rebase emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -345,6 +365,9 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/mocks/mock-strategy-manager.clar clarity-version: 2 + epoch: "2.4" + - id: 3 + transactions: - emulated-contract-publish: contract-name: rebase-1 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -355,9 +378,6 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/rules/rebase-1.clar clarity-version: 2 - epoch: "2.4" - - id: 3 - transactions: - emulated-contract-publish: contract-name: rebase-mock emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM diff --git a/scripts/lib/error-codes.ts b/scripts/lib/error-codes.ts index 04e9adf..bfe942f 100644 --- a/scripts/lib/error-codes.ts +++ b/scripts/lib/error-codes.ts @@ -28,9 +28,8 @@ export function createErrorsTable(simnet: Simnet, extractCheck: boolean) { const compareReadme = extractCheck && readme; - for (const [contractId, abi] of simnet.getContractsInterfaces()) { + for (const [contractId] of simnet.getContractsInterfaces()) { if (isTestContract(contractId)) continue; - console.log(abi); const source = simnet.getContractSource(contractId); if (!source) continue; const errorConstants = source.matchAll(constantErrRegex); diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 84d14d2..6cf4eb5 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -398,9 +398,10 @@ describe(contracts.endpoint, () => { console.log(response.events[1].data); expect(response.result).toBeOk(Cl.uint(1)); expect(response.events[0].event).toBe('stx_transfer_event'); - expect(response.events[1].event).toBe('print_event'); + expect(response.events[1].event).toBe('nft_mint_event'); + expect(response.events[2].event).toBe('print_event'); expect( - ((response.events[1].data.value as TupleCV).data.details as TupleCV).data['requested-at'] + ((response.events[2].data.value as TupleCV).data.details as TupleCV).data['requested-at'] ).toBeUint(2); }); }); From 40806356e306874a34b93b8147e3d8f9c9c43923 Mon Sep 17 00:00:00 2001 From: friedger Date: Thu, 21 Mar 2024 01:57:51 +0100 Subject: [PATCH 15/32] chore: add tests for events --- README.md | 4 +--- tests/lqstx-mint-endpoint-with-public-pools.test.ts | 1 - tests/lqstx-mint-endpoint.test.ts | 4 +++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e3bc89e..1034166 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,8 @@ are in the form `(err uint)` and they are unique across all contracts. ### Error table - | Contract | Constant | Value | Description | -| ----------------------------- | -------------------------------- | ----------- | ----------- | +|-------------------------------|----------------------------------|-------------|-------------| | lisa-dao | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint | err-unauthorised | (err u1000) | | | lqstx-mint-endpoint-v1-01 | err-unauthorised | (err u1000) | | @@ -132,7 +131,6 @@ are in the form `(err uint)` and they are unique across all contracts. | token-vesting | err-event-not-vested | (err u9002) | | | token-vesting | err-event-already-claimed | (err u9003) | | | token-vesting | err-recipient-exists | (err u9004) | | - ## References diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index b003e53..c454fa3 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -250,7 +250,6 @@ describe(contracts.endpoint, () => { ]); expect(responses[0].result).toBeErr(Cl.uint(7006)); // request pending expect(responses[1].result).toBeErr(Cl.uint(3000)); // not authorized - responses[2].events.map((e: any) => console.log(e)); expect(responses[2].result).toBeOk(Cl.uint(mintAmount)); // mintAmount stx transferred, mintAmount - 1 stx locked const stxAccountFastPoolMember1 = simnet.runSnippet( diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 6cf4eb5..48e50a4 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -254,10 +254,13 @@ describe(contracts.endpoint, () => { simnet.mineEmptyBlocks(mintDelay); response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); expect(response.result).toBeOk(Cl.bool(true)); + expect(response.events[2].event).toBe('nft_burn_event'); response = simnet.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user); expect(response.result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.buffer(new Uint8Array([1])) }) ); + expect(response.events[7].event).toBe('nft_mint_event'); + expect(response.events[17].event).toBe('nft_burn_event'); }); it('can interact with strategies', () => { @@ -395,7 +398,6 @@ describe(contracts.endpoint, () => { expect(getRequestCycle()).toBe(2n); const response = requestMint(); - console.log(response.events[1].data); expect(response.result).toBeOk(Cl.uint(1)); expect(response.events[0].event).toBe('stx_transfer_event'); expect(response.events[1].event).toBe('nft_mint_event'); From c3b0cfd1614d10a3b279f0951b33502e1b3bcd33 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Thu, 21 Mar 2024 22:20:43 +0800 Subject: [PATCH 16/32] lqstx => listx --- contracts/extensions/lqstx-mint-endpoint.clar | 2 +- contracts/proposals/lip001.clar | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 8a12281..db51c93 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -24,7 +24,7 @@ (define-data-var paused bool true) (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts -(define-data-var request-cutoff uint u100) ;; request must be made 100 blocks before prepare stage starts +(define-data-var request-cutoff uint u300) ;; request must be made 100 blocks before prepare stage starts ;; __IF_MAINNET__ (define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) diff --git a/contracts/proposals/lip001.clar b/contracts/proposals/lip001.clar index 57e9cd5..252465c 100644 --- a/contracts/proposals/lip001.clar +++ b/contracts/proposals/lip001.clar @@ -14,6 +14,11 @@ { extension: .rebase-1-v1-02, enabled: true } ))) + (try! (contract-call? .token-lqstx dao-set-name "liSTX")) + (try! (contract-call? .token-lqstx dao-set-symbol "liSTX")) + (try! (contract-call? .token-vlqstx dao-set-name "vliSTX")) + (try! (contract-call? .token-vlqstx dao-set-symbol "vliSTX")) + ;; Enable whitelist (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist true)) (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-whitelisted-many From e15f42c60ec26d6108b4adba0957939be10da823 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Thu, 21 Mar 2024 22:31:27 +0800 Subject: [PATCH 17/32] test updated --- contracts/extensions/lqstx-mint-endpoint.clar | 12 ++++------- ...tx-mint-endpoint-with-public-pools.test.ts | 10 +++++----- tests/lqstx-mint-endpoint.test.ts | 20 +++++++++---------- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index b75bf23..aa70f5a 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -90,18 +90,14 @@ ;; @dev get-reward-cycle measures end to end (define-read-only (get-reward-cycle (burn-block uint)) - (if (>= burn-block activation-burn-block) - (some (/ (- burn-block activation-burn-block) reward-cycle-length)) - none)) + (/ (- burn-block activation-burn-block) reward-cycle-length)) (define-read-only (get-first-burn-block-in-reward-cycle (reward-cycle uint)) (+ activation-burn-block (* reward-cycle-length reward-cycle))) ;; @dev get-request-cycle measures request-cutoff to request-cutoff (define-read-only (get-request-cycle (burn-block uint)) - (if (>= burn-block activation-burn-block) - (some (/ (- (+ burn-block prepare-cycle-length (var-get request-cutoff)) activation-burn-block) reward-cycle-length)) - none)) + (/ (- (+ burn-block prepare-cycle-length (var-get request-cutoff)) activation-burn-block) reward-cycle-length)) (define-read-only (get-first-burn-block-in-request-cycle (reward-cycle uint)) (- (+ activation-burn-block (* reward-cycle-length reward-cycle)) prepare-cycle-length (var-get request-cutoff))) @@ -121,7 +117,7 @@ (define-public (request-mint (amount uint)) (let ( (sender tx-sender) - (cycle (unwrap-panic (get-request-cycle burn-block-height))) + (cycle (get-request-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-not-paused-or-fail)) @@ -215,7 +211,7 @@ (define-public (request-burn (sender principal) (amount uint)) (let ( ;; @dev requested-at not used for burn - (cycle (unwrap-panic (get-request-cycle burn-block-height))) + (cycle (get-request-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)))) diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index b003e53..f444ccc 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -49,8 +49,8 @@ const getRewardCycle = () => { 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user - ).result as ResponseOkCV - ).value.value; + ).result as UIntCV + ).value; }; const getBlocksToStartOfCycle = (cycle: bigint) => { @@ -62,7 +62,7 @@ const getBlocksToStartOfCycle = (cycle: bigint) => { 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle)], user - ).result as ResponseOkCV + ).result as UIntCV ).value ) - simnet.blockHeight ); @@ -223,8 +223,8 @@ describe(contracts.endpoint, () => { 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user - ).result as ResponseOkCV - ).value.value; + ).result as UIntCV + ).value; const blocksToMine = Number( ( diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 84d14d2..5a581c3 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -59,8 +59,8 @@ const getRewardCycle = () => { 'get-reward-cycle', [Cl.uint(simnet.blockHeight)], user - ).result as ResponseOkCV - ).value.value; + ).result as UIntCV + ).value; }; const getRequestCycle = () => { @@ -70,14 +70,14 @@ const getRequestCycle = () => { 'get-request-cycle', [Cl.uint(simnet.blockHeight)], user - ).result as ResponseOkCV - ).value.value; + ).result as UIntCV + ).value; }; const getRequestCutoff = () => { return ( simnet.callReadOnlyFn(contracts.endpoint, 'get-request-cutoff', [], user) - .result as ResponseOkCV + .result as UIntCV ).value; }; const getBlocksToStartOfCycle = (cycle: bigint) => { @@ -89,7 +89,7 @@ const getBlocksToStartOfCycle = (cycle: bigint) => { 'get-first-burn-block-in-reward-cycle', [Cl.uint(cycle)], user - ).result as ResponseOkCV + ).result as UIntCV ).value ) - simnet.blockHeight ); @@ -378,20 +378,20 @@ describe(contracts.endpoint, () => { expect(getRequestCycle()).toBe(0n); // cycle length - prepare cycle length - cutoff - blocks for deployment and prepare - simnet.mineEmptyBlocks(1050 - 50 - 100 - 6); + simnet.mineEmptyBlocks(1050 - 50 - 300 - 6); // we are at the end of request cycle 0 - expect(simnet.blockHeight).toBe(899); + expect(simnet.blockHeight).toBe(699); expect(getRequestCycle()).toBe(0n); simnet.mineEmptyBlocks(1050); // cycle length // we are at end of request cycle 1 - expect(simnet.blockHeight).toBe(1949); + expect(simnet.blockHeight).toBe(1749); expect(getRequestCycle()).toBe(1n); simnet.mineEmptyBlocks(1); // we are at beginning of request cycle 2 // that is 1050 + 1050 - 50 - 100 - expect(simnet.blockHeight).toBe(1950); + expect(simnet.blockHeight).toBe(1750); expect(getRequestCycle()).toBe(2n); const response = requestMint(); From 90efdd3167f2eadcb4d7950a489323006bbfb8e4 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Thu, 21 Mar 2024 22:35:01 +0800 Subject: [PATCH 18/32] token name --- contracts/proposals/lip001.clar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/proposals/lip001.clar b/contracts/proposals/lip001.clar index 252465c..001011d 100644 --- a/contracts/proposals/lip001.clar +++ b/contracts/proposals/lip001.clar @@ -14,9 +14,9 @@ { extension: .rebase-1-v1-02, enabled: true } ))) - (try! (contract-call? .token-lqstx dao-set-name "liSTX")) + (try! (contract-call? .token-lqstx dao-set-name "Liberate your STX")) (try! (contract-call? .token-lqstx dao-set-symbol "liSTX")) - (try! (contract-call? .token-vlqstx dao-set-name "vliSTX")) + (try! (contract-call? .token-vlqstx dao-set-name "Vault your liSTX")) (try! (contract-call? .token-vlqstx dao-set-symbol "vliSTX")) ;; Enable whitelist From 467d6d4db42d6cb3ad2f59ac5ddd1fb4210625c1 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Thu, 21 Mar 2024 22:42:54 +0800 Subject: [PATCH 19/32] LiSTX --- contracts/proposals/lip001.clar | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/proposals/lip001.clar b/contracts/proposals/lip001.clar index 001011d..8e7ea35 100644 --- a/contracts/proposals/lip001.clar +++ b/contracts/proposals/lip001.clar @@ -14,10 +14,10 @@ { extension: .rebase-1-v1-02, enabled: true } ))) - (try! (contract-call? .token-lqstx dao-set-name "Liberate your STX")) - (try! (contract-call? .token-lqstx dao-set-symbol "liSTX")) - (try! (contract-call? .token-vlqstx dao-set-name "Vault your liSTX")) - (try! (contract-call? .token-vlqstx dao-set-symbol "vliSTX")) + (try! (contract-call? .token-lqstx dao-set-name "LiSTX")) + (try! (contract-call? .token-lqstx dao-set-symbol "LiSTX")) + (try! (contract-call? .token-vlqstx dao-set-name "vLiSTX")) + (try! (contract-call? .token-vlqstx dao-set-symbol "vLiSTX")) ;; Enable whitelist (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist true)) From 39a00c85a4b6d1f40cfcba73231d0ab66519a669 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Fri, 22 Mar 2024 20:15:52 +0800 Subject: [PATCH 20/32] print on lip001 --- contracts/proposals/lip001.clar | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/proposals/lip001.clar b/contracts/proposals/lip001.clar index 8e7ea35..2e17c6e 100644 --- a/contracts/proposals/lip001.clar +++ b/contracts/proposals/lip001.clar @@ -18,6 +18,7 @@ (try! (contract-call? .token-lqstx dao-set-symbol "LiSTX")) (try! (contract-call? .token-vlqstx dao-set-name "vLiSTX")) (try! (contract-call? .token-vlqstx dao-set-symbol "vLiSTX")) + (print { notification: "what-is-LISA", payload: "LISA is the goddess of liquid stacking. Liberate your STX with LiSTX!"}) ;; Enable whitelist (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist true)) From 33e8b799a7e4a095076e6de87cbf7b71ce597b66 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Fri, 22 Mar 2024 20:23:55 +0800 Subject: [PATCH 21/32] only dao-or-extension can burn nft --- contracts/extensions/lqstx-mint-endpoint.clar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 6d79895..6e8656d 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -141,7 +141,7 @@ (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))) - (try! (contract-call? .li-stx-mint-nft burn request-id)) + (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) (ok true))) (define-public (revoke-burn (request-id uint)) @@ -158,7 +158,7 @@ (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))) - (try! (contract-call? .li-stx-burn-nft burn request-id)) + (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) (ok true))) ;; governance calls From f47043414e2bcd59e0f4ddfbe812050e417b58d6 Mon Sep 17 00:00:00 2001 From: friedger Date: Fri, 22 Mar 2024 14:57:40 +0100 Subject: [PATCH 22/32] feat: use nft owner --- contracts/aux/li-stx-burn-nft.clar | 8 +- contracts/aux/li-stx-mint-nft.clar | 8 +- contracts/extensions/lqstx-mint-endpoint.clar | 26 ++-- tests/clients/mock-client.ts | 127 ++++++++++++++++++ tests/listx-nft.test.ts | 39 ++++++ ...tx-mint-endpoint-with-public-pools.test.ts | 3 +- tests/lqstx-mint-endpoint.test.ts | 127 +++--------------- tests/operators.test.ts | 38 +----- 8 files changed, 216 insertions(+), 160 deletions(-) create mode 100644 tests/clients/mock-client.ts create mode 100644 tests/listx-nft.test.ts diff --git a/contracts/aux/li-stx-burn-nft.clar b/contracts/aux/li-stx-burn-nft.clar index f0fe25f..85fc1d7 100644 --- a/contracts/aux/li-stx-burn-nft.clar +++ b/contracts/aux/li-stx-burn-nft.clar @@ -23,12 +23,12 @@ (define-data-var ipfs-root (string-ascii 80) "") (define-data-var metadata-frozen bool false) -(define-public (mint (id uint) (amount uint)) - (let ((current-balance (get-balance tx-sender))) +(define-public (mint (id uint) (amount uint) (recipient principal)) + (let ((current-balance (get-balance recipient))) (try! (is-dao-or-extension)) (var-set last-id id) - (map-set token-count tx-sender (+ current-balance u1)) - (nft-mint? li-stx-burn id tx-sender))) + (map-set token-count recipient (+ current-balance u1)) + (nft-mint? li-stx-burn id recipient))) (define-public (burn (token-id uint)) (let ((owner (unwrap! (nft-get-owner? li-stx-burn token-id) err-not-found)) diff --git a/contracts/aux/li-stx-mint-nft.clar b/contracts/aux/li-stx-mint-nft.clar index 534f2ad..0bb1ad4 100644 --- a/contracts/aux/li-stx-mint-nft.clar +++ b/contracts/aux/li-stx-mint-nft.clar @@ -23,12 +23,12 @@ (define-data-var ipfs-root (string-ascii 80) "") (define-data-var metadata-frozen bool false) -(define-public (mint (id uint) (amount uint)) - (let ((current-balance (get-balance tx-sender))) +(define-public (mint (id uint) (amount uint) (recipient principal)) + (let ((current-balance (get-balance recipient))) (try! (is-dao-or-extension)) (var-set last-id id) - (map-set token-count tx-sender (+ current-balance u1)) - (nft-mint? li-stx-mint id tx-sender))) + (map-set token-count recipient (+ current-balance u1)) + (nft-mint? li-stx-mint id recipient))) (define-public (burn (token-id uint)) (let ((owner (unwrap! (nft-get-owner? li-stx-mint token-id) err-not-found)) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 6d79895..39821ef 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -72,6 +72,12 @@ (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 (get-owner-mint-nft (id uint)) + (contract-call? .li-stx-mint-nft get-owner id)) + +(define-read-only (get-owner-burn-nft (id uint)) + (contract-call? .li-stx-burn-nft get-owner id)) + (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))) @@ -125,7 +131,7 @@ (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)))) - (try! (contract-call? .li-stx-mint-nft mint request-id amount)) + (try! (contract-call? .li-stx-mint-nft mint request-id amount sender)) (print { type: "mint-request", id: request-id, details: request-details }) (ok request-id))) @@ -133,11 +139,12 @@ (let ( (request-details (try! (get-mint-request-or-fail request-id))) (mint-requests (get-mint-requests-pending-or-default (get requested-by request-details))) + (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked)) (request-id-idx (unwrap! (index-of? mint-requests request-id) err-request-finalized-or-revoked))) (try! (is-not-paused-or-fail)) - (asserts! (is-eq tx-sender (get requested-by request-details)) err-unauthorised) + (asserts! (is-eq tx-sender recipient) 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-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get amount request-details), recipient: recipient })))) (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))) @@ -148,14 +155,15 @@ (let ( (request-details (try! (get-burn-request-or-fail request-id))) (burn-requests (get-burn-requests-pending-or-default (get requested-by request-details))) + (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) (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-not-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) + (asserts! (is-eq tx-sender recipient) 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? .token-lqstx transfer lqstx-amount (as-contract tx-sender) recipient 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))) (try! (contract-call? .li-stx-burn-nft burn request-id)) @@ -199,10 +207,11 @@ (let ( (request-details (try! (get-mint-request-or-fail request-id))) (mint-requests (get-mint-requests-pending-or-default (get requested-by request-details))) + (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked)) (request-id-idx (try! (validate-mint-request request-id)))) (try! (is-not-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? .token-lqstx dao-mint (get amount request-details) recipient)) (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))) @@ -224,7 +233,7 @@ (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)))) - (try! (contract-call? .li-stx-burn-nft mint request-id amount)) + (try! (contract-call? .li-stx-burn-nft mint request-id amount sender)) (print { type: "burn-request", id: request-id, details: request-details }) (ok { request-id: request-id, status: PENDING }))) @@ -233,12 +242,13 @@ (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))) + (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) (validation-data (try! (validate-burn-request request-id)))) (try! (is-not-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-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get vaulted-amount validation-data), recipient: recipient })))) (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)))) (try! (contract-call? .li-stx-burn-nft burn request-id)) diff --git a/tests/clients/mock-client.ts b/tests/clients/mock-client.ts new file mode 100644 index 0000000..dc833ad --- /dev/null +++ b/tests/clients/mock-client.ts @@ -0,0 +1,127 @@ +import { tx } from '@hirosystems/clarinet-sdk'; +import { IntegerType } from '@stacks/common'; +import { BufferCV, Cl, ResponseOkCV, UIntCV } from '@stacks/transactions'; + +export const createClientMockSetup = () => { + const accounts = simnet.getAccounts(); + const user = accounts.get('wallet_1')!; + const oracle = accounts.get('wallet_2')!; + const bot = accounts.get('wallet_3')!; + const manager = accounts.get('wallet_4')!; + const operator3 = accounts.get('wallet_5')!; + + const contracts = { + endpoint: 'lqstx-mint-endpoint-v1-02', + registry: 'lqstx-mint-registry', + vault: 'lqstx-vault', + lqstx: 'token-lqstx', + vlqstx: 'token-vlqstx', + wstx: 'token-wstx', + strategy: 'mock-strategy', + rebase: 'lisa-rebase-v1-02', + rebase1: 'rebase-mock', + amm: 'amm-swap-pool-v1-1', + wlqstx: 'token-wlqstx', + dao: 'lisa-dao', + boot: 'regtest-boot', + manager: 'mock-strategy-manager', + operators: 'operators', + proposal: 'mock-proposal', + proposal2: 'mock-proposal', + mintNft: 'li-stx-mint-nft', + burnNft: 'li-stx-burn-nft', + }; + + const prepareTest = () => + simnet.mineBlock([ + tx.callPublicFn( + contracts.dao, + 'construct', + [Cl.contractPrincipal(simnet.deployer, contracts.boot)], + simnet.deployer + ), + ]); + + const requestMint = (amount: IntegerType) => + simnet.callPublicFn(contracts.endpoint, 'request-mint', [Cl.uint(amount)], user); + + const createPayload = (amount: IntegerType) => + ( + simnet.callReadOnlyFn(contracts.strategy, 'create-payload', [Cl.uint(amount)], manager) + .result as BufferCV + ).buffer; + + const getRewardCycle = () => { + return ( + simnet.callReadOnlyFn( + contracts.endpoint, + 'get-reward-cycle', + [Cl.uint(simnet.blockHeight)], + user + ).result as UIntCV + ).value; + }; + + const getRequestCycle = () => { + return ( + simnet.callReadOnlyFn( + contracts.endpoint, + 'get-request-cycle', + [Cl.uint(simnet.blockHeight)], + user + ).result as UIntCV + ).value; + }; + + const getRequestCutoff = () => { + return ( + simnet.callReadOnlyFn(contracts.endpoint, 'get-request-cutoff', [], user).result as UIntCV + ).value; + }; + + const getBlocksToStartOfCycle = (cycle: bigint) => { + return ( + Number( + ( + simnet.callReadOnlyFn( + contracts.endpoint, + 'get-first-burn-block-in-reward-cycle', + [Cl.uint(cycle)], + user + ).result as UIntCV + ).value + ) - simnet.blockHeight + ); + }; + + const goToNextCycle = () => { + const cycle = getRewardCycle(); + const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); + + simnet.mineEmptyBlocks(blocksToMine); + }; + + const liSTXBalance = (user: string) => { + return ( + simnet.callReadOnlyFn(contracts.lqstx, 'get-balance', [Cl.standardPrincipal(user)], user) + .result as ResponseOkCV + ).value; + }; + return { + contracts, + prepareTest, + requestMint, + createPayload, + getRewardCycle, + getRequestCycle, + getBlocksToStartOfCycle, + goToNextCycle, + getRequestCutoff, + liSTXBalance, + user, + oracle, + bot, + manager, + operator3, + }; +}; diff --git a/tests/listx-nft.test.ts b/tests/listx-nft.test.ts new file mode 100644 index 0000000..ce1ea58 --- /dev/null +++ b/tests/listx-nft.test.ts @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BUSL-1.1 + +import { Cl } from '@stacks/transactions'; +import { describe, expect, it } from 'vitest'; +import { createClientMockSetup } from './clients/mock-client'; + +const { contracts, prepareTest, requestMint, goToNextCycle, liSTXBalance, user, bot } = + createClientMockSetup(); + +const mintDelay = 14; + +const transferMintNFT = (nftId: number, account: string) => { + return simnet.callPublicFn( + contracts.mintNft, + 'transfer', + [Cl.uint(nftId), Cl.standardPrincipal(user), Cl.standardPrincipal(account)], + user + ); +}; + +describe('LiSTX NFT', () => { + it('user can transfer nft before finalize mint', () => { + prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); + let response = requestMint(100e6); + expect(response.result).toBeOk(Cl.uint(1)); + + // transfer nft to bot + response = transferMintNFT(1, bot); + expect(response.result).toBeOk(Cl.bool(true)); + // finalize mint + goToNextCycle(); + simnet.mineEmptyBlocks(mintDelay); + simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + + // check that bot received liquid stx + expect(liSTXBalance(user)).toBeUint(0); + expect(liSTXBalance(bot)).toBeUint(100e6); + }); +}); diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index 84970ca..28a9ee7 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import { tx } from '@hirosystems/clarinet-sdk'; -import { Cl, ResponseOkCV, TupleCV, UIntCV, cvToString } from '@stacks/transactions'; +import { Cl, TupleCV, UIntCV } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; const mintDelay = 432; @@ -150,7 +150,6 @@ describe(contracts.endpoint, () => { expect(responses[1].result).toBeOk(Cl.bool(true)); expect(responses[2].result).toBeOk(Cl.uint(mintAmount)); expect(responses[3].result).toBeOk(Cl.uint(mintAmount)); - console.log(cvToString(responses[4].result)); expect(responses[4].result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index d6dc932..77778d2 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -1,49 +1,29 @@ // SPDX-License-Identifier: BUSL-1.1 import { tx } from '@hirosystems/clarinet-sdk'; -import { Cl, ResponseOkCV, TupleCV, UIntCV } from '@stacks/transactions'; +import { Cl, TupleCV } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; +import { createClientMockSetup } from './clients/mock-client'; -const accounts = simnet.getAccounts(); -const user = accounts.get('wallet_1')!; -const oracle = accounts.get('wallet_2')!; -const bot = accounts.get('wallet_3')!; -const manager = accounts.get('wallet_4')!; +const { + contracts, + prepareTest, + user, + oracle, + bot, + manager, + requestMint: requestMintLib, + createPayload, + goToNextCycle, + getRequestCycle, + getRewardCycle, + getBlocksToStartOfCycle, +} = createClientMockSetup(); -const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-02', - registry: 'lqstx-mint-registry', - vault: 'lqstx-vault', - lqstx: 'token-lqstx', - vlqstx: 'token-vlqstx', - wstx: 'token-wstx', - strategy: 'mock-strategy', - rebase: 'lisa-rebase-v1-02', - rebase1: 'rebase-mock', - amm: 'amm-swap-pool-v1-1', - wlqstx: 'token-wlqstx', - dao: 'lisa-dao', - boot: 'regtest-boot', - manager: 'mock-strategy-manager', - operators: 'operators', - proposal: 'mock-proposal', -}; const mintDelay = 144; +const requestMint = () => requestMintLib(100e6); -const prepareTest = () => - simnet.mineBlock([ - tx.callPublicFn( - contracts.dao, - 'construct', - [Cl.contractPrincipal(simnet.deployer, contracts.boot)], - simnet.deployer - ), - ]); - -const requestMint = () => - simnet.callPublicFn(contracts.endpoint, 'request-mint', [Cl.uint(100e6)], user); - -const requestBurn = (payload: Buffer) => +const requestBurn = (payload: Uint8Array) => simnet.mineBlock([ tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), @@ -52,56 +32,6 @@ const requestBurn = (payload: Buffer) => tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user), ]); -const getRewardCycle = () => { - return ( - simnet.callReadOnlyFn( - contracts.endpoint, - 'get-reward-cycle', - [Cl.uint(simnet.blockHeight)], - user - ).result as UIntCV - ).value; -}; - -const getRequestCycle = () => { - return ( - simnet.callReadOnlyFn( - contracts.endpoint, - 'get-request-cycle', - [Cl.uint(simnet.blockHeight)], - user - ).result as UIntCV - ).value; -}; - -const getRequestCutoff = () => { - return ( - simnet.callReadOnlyFn(contracts.endpoint, 'get-request-cutoff', [], user) - .result as UIntCV - ).value; -}; -const getBlocksToStartOfCycle = (cycle: bigint) => { - return ( - Number( - ( - simnet.callReadOnlyFn( - contracts.endpoint, - 'get-first-burn-block-in-reward-cycle', - [Cl.uint(cycle)], - user - ).result as UIntCV - ).value - ) - simnet.blockHeight - ); -}; - -const goToNextCycle = () => { - const cycle = getRewardCycle(); - const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); - - simnet.mineEmptyBlocks(blocksToMine); -}; - describe(contracts.endpoint, () => { it('can request mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); @@ -157,12 +87,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - const payload = simnet.callReadOnlyFn( - contracts.strategy, - 'create-payload', - [Cl.uint(100e6)], - manager - ).result.buffer; + const payload = createPayload(100e6); const responses = requestBurn(payload); expect(responses[0].result).toBeOk(Cl.uint(0)); expect(responses[1].result).toBeOk(Cl.bool(true)); @@ -181,12 +106,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - const payload = simnet.callReadOnlyFn( - contracts.strategy, - 'create-payload', - [Cl.uint(100e6)], - manager - ).result.buffer; + const payload = createPayload(100e6); const burnResponses = requestBurn(payload); expect(burnResponses[0].result).toBeOk(Cl.uint(0)); expect(burnResponses[1].result).toBeOk(Cl.bool(true)); @@ -215,12 +135,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - const payload = simnet.callReadOnlyFn( - contracts.strategy, - 'create-payload', - [Cl.uint(100e6)], - manager - ).result.buffer; + const payload = createPayload(100e6); const burnResponses = requestBurn(payload); expect(burnResponses[0].result).toBeOk(Cl.uint(0)); expect(burnResponses[1].result).toBeOk(Cl.bool(true)); diff --git a/tests/operators.test.ts b/tests/operators.test.ts index dc9641c..42da7e7 100644 --- a/tests/operators.test.ts +++ b/tests/operators.test.ts @@ -1,46 +1,12 @@ - // SPDX-License-Identifier: BUSL-1.1 import { ParsedTransactionResult, tx } from '@hirosystems/clarinet-sdk'; import { BooleanCV, Cl, IntCV, SomeCV, TupleCV, UIntCV } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; +import { createClientMockSetup } from './clients/mock-client'; -const accounts = simnet.getAccounts(); -const user = accounts.get('wallet_1')!; -const oracle = accounts.get('wallet_2')!; -const bot = accounts.get('wallet_3')!; -const manager = accounts.get('wallet_4')!; -const operator3 = accounts.get('wallet_5')!; +const { contracts, prepareTest, bot, manager, operator3 } = createClientMockSetup(); -const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-02', - registry: 'lqstx-mint-registry', - vault: 'lqstx-vault', - lqstx: 'token-lqstx', - vlqstx: 'token-vlqstx', - wstx: 'token-wstx', - strategy: 'mock-strategy', - rebase: 'lisa-rebase-v1-02', - rebase1: 'rebase-mock', - amm: 'amm-swap-pool-v1-1', - wlqstx: 'token-wlqstx', - dao: 'lisa-dao', - boot: 'regtest-boot', - manager: 'mock-strategy-manager', - operators: 'operators', - proposal: 'mock-proposal', - proposal2: 'mock-proposal', -}; - -const prepareTest = () => - simnet.mineBlock([ - tx.callPublicFn( - contracts.dao, - 'construct', - [Cl.contractPrincipal(simnet.deployer, contracts.boot)], - simnet.deployer - ), - ]); const expectProposalDataToBe = (proposedAt: number, signals: number, executed: boolean) => { const proposalData = simnet.getMapEntry( contracts.operators, From 0c487761ed5aa8bdf6e62aec5f2fe604df7f37bb Mon Sep 17 00:00:00 2001 From: friedger Date: Fri, 22 Mar 2024 15:17:55 +0100 Subject: [PATCH 23/32] chore: remove requested-by from endpoint --- contracts/extensions/lqstx-mint-endpoint.clar | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 73238da..b42279f 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -81,18 +81,18 @@ (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))) + (recipient (unwrap! (get-owner-mint-nft request-id) err-request-finalized-or-revoked))) (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))) + (ok recipient))) ;; @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)) + (recipient (unwrap! (get-owner-burn-nft 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 }))) + (ok { vaulted-amount: vaulted-amount, recipient: recipient }))) ;; @dev get-reward-cycle measures end to end (define-read-only (get-reward-cycle (burn-block uint)) @@ -130,7 +130,6 @@ (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)))) (try! (contract-call? .li-stx-mint-nft mint request-id amount sender)) (print { type: "mint-request", id: request-id, details: request-details }) (ok request-id))) @@ -138,25 +137,20 @@ (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))) - (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked)) - (request-id-idx (unwrap! (index-of? mint-requests request-id) err-request-finalized-or-revoked))) + (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) (try! (is-not-paused-or-fail)) (asserts! (is-eq tx-sender recipient) 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: recipient })))) (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))) (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) (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))) (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) - (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-not-paused-or-fail)) (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) @@ -165,7 +159,6 @@ (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) recipient 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))) (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) (ok true))) @@ -206,15 +199,13 @@ (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))) - (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked)) - (request-id-idx (try! (validate-mint-request request-id)))) + (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) + (try! (validate-mint-request request-id)) (try! (is-not-paused-or-fail)) (try! (is-dao-or-extension)) (try! (contract-call? .token-lqstx dao-mint (get amount request-details) recipient)) (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))) (try! (contract-call? .li-stx-mint-nft burn request-id)) (ok true))) @@ -232,7 +223,6 @@ (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)))) (try! (contract-call? .li-stx-burn-nft mint request-id amount sender)) (print { type: "burn-request", id: request-id, details: request-details }) (ok { request-id: request-id, status: PENDING }))) @@ -241,7 +231,6 @@ (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))) (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) (validation-data (try! (validate-burn-request request-id)))) (try! (is-not-paused-or-fail)) @@ -250,7 +239,6 @@ (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: recipient })))) (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)))) (try! (contract-call? .li-stx-burn-nft burn request-id)) (ok true))) From cfbe460792d465ae5e1382ec1816f70254e5390d Mon Sep 17 00:00:00 2001 From: friedger Date: Fri, 22 Mar 2024 18:41:43 +0100 Subject: [PATCH 24/32] fix: use max id as last-token-id --- contracts/aux/li-stx-burn-nft.clar | 6 +- contracts/aux/li-stx-mint-nft.clar | 6 +- contracts/extensions/lqstx-mint-endpoint.clar | 1 - package.json | 2 +- tests/clients/mock-client.ts | 4 ++ tests/listx-nft.test.ts | 65 ++++++++++++++++++- ...tx-mint-endpoint-with-public-pools.test.ts | 41 ++++++++++++ 7 files changed, 118 insertions(+), 7 deletions(-) diff --git a/contracts/aux/li-stx-burn-nft.clar b/contracts/aux/li-stx-burn-nft.clar index 85fc1d7..edfd966 100644 --- a/contracts/aux/li-stx-burn-nft.clar +++ b/contracts/aux/li-stx-burn-nft.clar @@ -23,10 +23,12 @@ (define-data-var ipfs-root (string-ascii 80) "") (define-data-var metadata-frozen bool false) +(define-read-only (max (a uint) (b uint)) (if (> a b) a b)) + (define-public (mint (id uint) (amount uint) (recipient principal)) (let ((current-balance (get-balance recipient))) (try! (is-dao-or-extension)) - (var-set last-id id) + (var-set last-id (max id (var-get last-id))) (map-set token-count recipient (+ current-balance u1)) (nft-mint? li-stx-burn id recipient))) @@ -70,7 +72,7 @@ (ok (nft-get-owner? li-stx-burn token-id))) (define-read-only (get-last-token-id) - (ok (- (var-get last-id) u1))) + (ok (var-get last-id))) (define-read-only (get-token-uri (token-id uint)) (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) diff --git a/contracts/aux/li-stx-mint-nft.clar b/contracts/aux/li-stx-mint-nft.clar index 0bb1ad4..18afa83 100644 --- a/contracts/aux/li-stx-mint-nft.clar +++ b/contracts/aux/li-stx-mint-nft.clar @@ -23,10 +23,12 @@ (define-data-var ipfs-root (string-ascii 80) "") (define-data-var metadata-frozen bool false) +(define-read-only (max (a uint) (b uint)) (if (> a b) a b)) + (define-public (mint (id uint) (amount uint) (recipient principal)) (let ((current-balance (get-balance recipient))) (try! (is-dao-or-extension)) - (var-set last-id id) + (var-set last-id (max id (var-get last-id))) (map-set token-count recipient (+ current-balance u1)) (nft-mint? li-stx-mint id recipient))) @@ -70,7 +72,7 @@ (ok (nft-get-owner? li-stx-mint token-id))) (define-read-only (get-last-token-id) - (ok (- (var-get last-id) u1))) + (ok (var-get last-id))) (define-read-only (get-token-uri (token-id uint)) (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index b42279f..eb825a3 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -214,7 +214,6 @@ (define-public (request-burn (sender principal) (amount uint)) (let ( - ;; @dev requested-at not used for burn (cycle (get-request-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 }) diff --git a/package.json b/package.json index b392cd5..3324cb3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "setup:clarity": "./scripts/clarinet_manager.sh clean && ./scripts/clarinet_manager.sh install", "test": "npm run replace:mainnet && vitest run && npm run replace:testnet", "test:init": "vitest run -t notests", - "test:report": "npm run replace:testnet && vitest run -- --coverage --costs && npm run replace:testnet", + "test:report": "npm run replace:mainnet && vitest run -- --coverage --costs && npm run replace:testnet", "test:watch": "chokidar \"tests/**/*.ts\" \"contracts/**/*.clar\" -c \"npm run test:report\"", "generate:report": "genhtml --branch-coverage -o coverage lcov.info" }, diff --git a/tests/clients/mock-client.ts b/tests/clients/mock-client.ts index dc833ad..f6d73cc 100644 --- a/tests/clients/mock-client.ts +++ b/tests/clients/mock-client.ts @@ -45,6 +45,9 @@ export const createClientMockSetup = () => { const requestMint = (amount: IntegerType) => simnet.callPublicFn(contracts.endpoint, 'request-mint', [Cl.uint(amount)], user); + const requestBurn = (amount: IntegerType) => + simnet.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(amount)], user); + const createPayload = (amount: IntegerType) => ( simnet.callReadOnlyFn(contracts.strategy, 'create-payload', [Cl.uint(amount)], manager) @@ -111,6 +114,7 @@ export const createClientMockSetup = () => { contracts, prepareTest, requestMint, + requestBurn, createPayload, getRewardCycle, getRequestCycle, diff --git a/tests/listx-nft.test.ts b/tests/listx-nft.test.ts index ce1ea58..1e81f94 100644 --- a/tests/listx-nft.test.ts +++ b/tests/listx-nft.test.ts @@ -4,7 +4,7 @@ import { Cl } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; import { createClientMockSetup } from './clients/mock-client'; -const { contracts, prepareTest, requestMint, goToNextCycle, liSTXBalance, user, bot } = +const { contracts, prepareTest, requestMint, requestBurn, goToNextCycle, liSTXBalance, user, bot } = createClientMockSetup(); const mintDelay = 14; @@ -18,6 +18,15 @@ const transferMintNFT = (nftId: number, account: string) => { ); }; +const transferBurnNFT = (nftId: number, account: string) => { + return simnet.callPublicFn( + contracts.burnNft, + 'transfer', + [Cl.uint(nftId), Cl.standardPrincipal(user), Cl.standardPrincipal(account)], + user + ); +}; + describe('LiSTX NFT', () => { it('user can transfer nft before finalize mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); @@ -36,4 +45,58 @@ describe('LiSTX NFT', () => { expect(liSTXBalance(user)).toBeUint(0); expect(liSTXBalance(bot)).toBeUint(100e6); }); + + it('new owner can revoke mint', () => { + prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); + let response = requestMint(100e6); + expect(response.result).toBeOk(Cl.uint(1)); + + // transfer nft to bot + response = transferMintNFT(1, bot); + expect(response.result).toBeOk(Cl.bool(true)); + + response = simnet.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], bot); + expect(response.result).toBeOk(Cl.bool(true)); + + // check that bot received stx + expect(simnet.getAssetsMap().get('STX')?.get(bot)).toBe(100000100000000n); + expect(simnet.getAssetsMap().get('STX')?.get(user)).toBe(99999900000000n); + }); + + it('there is no burn nft when liquid token is burnt immediately', () => { + prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); + let response; + + // request and finalize mint + response = requestMint(100e6); + expect(response.result).toBeOk(Cl.uint(1)); + goToNextCycle(); + simnet.mineEmptyBlocks(mintDelay); + response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + expect(response.result).toBeOk(Cl.bool(true)); + + // request burn + response = requestBurn(60e6); + expect(response.result).toBeOk( + Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('01') }) + ); + response = requestBurn(40e6); + expect(response.result).toBeOk( + Cl.tuple({ 'request-id': Cl.uint(2), status: Cl.bufferFromHex('01') }) + ); + // nft was already burnt + expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-owner', [Cl.uint(1)], user).result).toBeOk( + Cl.none() + ); + expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-owner', [Cl.uint(2)], user).result).toBeOk( + Cl.none() + ); + expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-last-token-id', [], user).result).toBeOk( + Cl.uint(2) + ); + + // check that bot received stx + expect(simnet.getAssetsMap().get('STX')?.get(bot)).toBe(100000000000000n); + expect(simnet.getAssetsMap().get('STX')?.get(user)).toBe(100000000000000n); + }); }); diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index 28a9ee7..00bb846 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -30,6 +30,7 @@ const contracts = { manager: 'public-pools-strategy-manager', operators: 'operators', proposal: 'mock-proposal', + burnNft: 'li-stx-burn-nft', }; const prepareTest = () => @@ -425,4 +426,44 @@ describe(contracts.endpoint, () => { expect(responses[0].result).toBeOk(Cl.bool(true)); expect(responses[1].result).toBeOk(Cl.bool(true)); }); + + it('user can transfer burn nft', () => { + prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); + let response; + + // request and finalize mint for 1m STX + response = requestMint(); + expect(response.result).toBeOk(Cl.uint(1)); + goToNextCycle(); + simnet.mineEmptyBlocks(mintDelay); + response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + expect(response.result).toBeOk(Cl.bool(true)); + + // request burn + requestBurn(); + + // transfer burn of 1 stx + response = simnet.callPublicFn( + contracts.burnNft, + 'transfer', + [Cl.uint(1), Cl.standardPrincipal(user), Cl.standardPrincipal(bot)], + user + ); + + // bot is now owning the nft + expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-owner', [Cl.uint(1)], user).result).toBeOk( + Cl.some(Cl.standardPrincipal(bot)) + ); + + simnet.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), + (response = simnet.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot)); + expect(response.result).toBeOk(Cl.bool(true)); + + // check that bot received stx + expect(simnet.getAssetsMap().get('STX')?.get(bot)).toBe(100000001_000_000n); + expect(simnet.getAssetsMap().get('STX')?.get(user)).toBe(99000000_000_000n); + + // check that user has 1m - 1 liquid stx + expect(simnet.getAssetsMap().get('.token-lqstx.lqstx')?.get(user)).toBe(999999_000_000n); + }); }); From b6a636fb2354e88b73badf4176b91996f538003f Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Sat, 23 Mar 2024 10:03:45 +0800 Subject: [PATCH 25/32] feat: inline traits for regtest deployments --- Clarinet.toml | 8 ++++++++ contracts/aux/li-stx-burn-nft.clar | 10 ++++++++-- contracts/aux/li-stx-mint-nft.clar | 11 +++++++++-- contracts/traits/commission-trait.clar | 2 ++ contracts/traits/nft-trait.clar | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 contracts/traits/commission-trait.clar create mode 100644 contracts/traits/nft-trait.clar diff --git a/Clarinet.toml b/Clarinet.toml index b21ee74..d760b64 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -45,6 +45,14 @@ epoch = 2.4 path = "contracts/traits/sip-010-trait.clar" epoch = 2.4 +[contracts.nft-trait] +path = "contracts/traits/nft-trait.clar" +epoch = 2.4 + +[contracts.commission-trait] +path = "contracts/traits/commission-trait.clar" +epoch = 2.4 + [contracts.strategy-trait] path = "contracts/traits/strategy-trait.clar" epoch = 2.4 diff --git a/contracts/aux/li-stx-burn-nft.clar b/contracts/aux/li-stx-burn-nft.clar index edfd966..cfbceb9 100644 --- a/contracts/aux/li-stx-burn-nft.clar +++ b/contracts/aux/li-stx-burn-nft.clar @@ -1,7 +1,10 @@ ;; li-stx-burn ;; contractType: public +;; __IF_MAINNET__ (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait) +;; (impl-trait .nft-trait.nft-trait) +;; __ENDIF__ (define-non-fungible-token li-stx-burn uint) @@ -34,7 +37,7 @@ (define-public (burn (token-id uint)) (let ((owner (unwrap! (nft-get-owner? li-stx-burn token-id) err-not-found)) - (current-balance (get-balance owner))) + (current-balance (get-balance owner))) (try! (is-dao-or-extension)) (asserts! (is-none (map-get? market token-id)) err-listing) (try! (nft-burn? li-stx-burn token-id owner)) @@ -78,7 +81,10 @@ (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) ;; Non-custodial marketplace extras +;; __IF_MAINNET__ (use-trait commission-trait 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait.commission) +;; (use-trait commission-trait .commission-trait.commission) +;; __ENDIF__ (define-map token-count principal uint) (define-map market uint {price: uint, commission: principal, royalty: uint}) @@ -135,4 +141,4 @@ (map-delete market id) (print {a: "buy-in-ustx", id: id}) (ok true))) - + diff --git a/contracts/aux/li-stx-mint-nft.clar b/contracts/aux/li-stx-mint-nft.clar index 18afa83..6dc4790 100644 --- a/contracts/aux/li-stx-mint-nft.clar +++ b/contracts/aux/li-stx-mint-nft.clar @@ -1,7 +1,10 @@ ;; li-stx-mint ;; contractType: public +;; __IF_MAINNET__ (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait) +;; (impl-trait .nft-trait.nft-trait) +;; __ENDIF__ (define-non-fungible-token li-stx-mint uint) @@ -34,7 +37,7 @@ (define-public (burn (token-id uint)) (let ((owner (unwrap! (nft-get-owner? li-stx-mint token-id) err-not-found)) - (current-balance (get-balance owner))) + (current-balance (get-balance owner))) (try! (is-dao-or-extension)) (asserts! (is-none (map-get? market token-id)) err-listing) (try! (nft-burn? li-stx-mint token-id owner)) @@ -78,7 +81,11 @@ (ok (some (concat (concat (var-get ipfs-root) "{id}") ".json")))) ;; Non-custodial marketplace extras +;; __IF_MAINNET__ (use-trait commission-trait 'SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.commission-trait.commission) +;; (use-trait commission-trait .commission-trait.commission) +;; __ENDIF__ + (define-map token-count principal uint) (define-map market uint {price: uint, commission: principal, royalty: uint}) @@ -135,4 +142,4 @@ (map-delete market id) (print {a: "buy-in-ustx", id: id}) (ok true))) - + diff --git a/contracts/traits/commission-trait.clar b/contracts/traits/commission-trait.clar new file mode 100644 index 0000000..4d26d52 --- /dev/null +++ b/contracts/traits/commission-trait.clar @@ -0,0 +1,2 @@ +(define-trait commission + ((pay (uint uint) (response bool uint)))) diff --git a/contracts/traits/nft-trait.clar b/contracts/traits/nft-trait.clar new file mode 100644 index 0000000..cc558fd --- /dev/null +++ b/contracts/traits/nft-trait.clar @@ -0,0 +1,15 @@ +(define-trait nft-trait + ( + ;; Last token ID, limited to uint range + (get-last-token-id () (response uint uint)) + + ;; URI for metadata associated with the token + (get-token-uri (uint) (response (optional (string-ascii 256)) uint)) + + ;; Owner of a given token identifier + (get-owner (uint) (response (optional principal) uint)) + + ;; Transfer from the sender to a new principal + (transfer (uint principal principal) (response bool uint)) + ) +) From 00f7f1fcdb016ed56a32ed14f04489887daf12d8 Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Sat, 23 Mar 2024 11:50:38 +0800 Subject: [PATCH 26/32] fix: regtest rebase contract permission --- contracts/regtest-boot.clar | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index 1cebead..d88dc57 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -9,6 +9,10 @@ {extension: .lqstx-mint-endpoint, enabled: false} {extension: .lqstx-mint-endpoint-v1-02, enabled: true} {extension: .lisa-rebase-v1-02, enabled: true} + ;; __IF_MAINNET__ + {extension: .rebase-mock, enabled: true} + ;; {extension: .rebase-1-v1-02, enabled: true} + ;; __ENDIF__ {extension: .rebase-mock, enabled: true} {extension: .mock-strategy-manager, enabled: true} {extension: .lqstx-vault, enabled: true} From 2a07b1ff8c527c3284e1a27a97b6a3db1863989a Mon Sep 17 00:00:00 2001 From: friedger Date: Sat, 23 Mar 2024 16:35:29 +0100 Subject: [PATCH 27/32] chore: add sip10 tests --- tests/clients/sip10-client.ts | 29 +++++++++++++++++++++++++++++ tests/tokens.test.ts | 18 ++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/clients/sip10-client.ts create mode 100644 tests/tokens.test.ts diff --git a/tests/clients/sip10-client.ts b/tests/clients/sip10-client.ts new file mode 100644 index 0000000..0992c6c --- /dev/null +++ b/tests/clients/sip10-client.ts @@ -0,0 +1,29 @@ +import { Cl, ClarityType, cvToString } from '@stacks/transactions'; +import { expect, it } from 'vitest'; + +export const sip10Tests = (contract: string) => { + const accounts = simnet.getAccounts(); + const alice = accounts.get('wallet_1')!; + const bob = accounts.get('wallet_2')!; + + it('owner can transfer', () => { + let response = simnet.callPublicFn( + contract, + 'transfer', + [Cl.uint(1), Cl.standardPrincipal(alice), Cl.standardPrincipal(bob), Cl.none()], + alice + ); + console.log('transfer', cvToString(response.result)); + expect(response.result).toBeOk(Cl.bool(true)); + }); + + it('owner cannot transfer to owner', () => { + let response = simnet.callPublicFn( + contract, + 'transfer', + [Cl.uint(1), Cl.standardPrincipal(alice), Cl.standardPrincipal(alice), Cl.none()], + alice + ); + expect(response.result).toHaveClarityType(ClarityType.ResponseErr); + }); +}; diff --git a/tests/tokens.test.ts b/tests/tokens.test.ts new file mode 100644 index 0000000..dfdb754 --- /dev/null +++ b/tests/tokens.test.ts @@ -0,0 +1,18 @@ +import { Cl } from '@stacks/transactions'; +import { beforeEach, describe, expect } from 'vitest'; +import { createClientMockSetup } from './clients/mock-client'; +import { sip10Tests } from './clients/sip10-client.ts'; +const { goToNextCycle, requestMint, prepareTest, contracts, bot } = createClientMockSetup(); +const mintDelay = 14; + +describe('lisa token', () => { + beforeEach(() => { + prepareTest().map(r => expect(r.result).toBeOk(Cl.bool(true))); + requestMint(100e6); + goToNextCycle(); + simnet.mineEmptyBlocks(mintDelay); + simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + }); + + sip10Tests(contracts.lqstx); +}); From 492e034b8c20b359eaf4f1139f806c912ab6a813 Mon Sep 17 00:00:00 2001 From: friedger Date: Sat, 23 Mar 2024 17:18:37 +0100 Subject: [PATCH 28/32] fix: improve nft post conditions --- contracts/extensions/lqstx-mint-endpoint.clar | 14 ++++++++++++-- contracts/rules/rebase-1.clar | 9 +++------ tests/listx-nft.test.ts | 4 ++-- tests/lqstx-mint-endpoint.test.ts | 6 ++++-- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index eb825a3..78c494a 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -222,9 +222,19 @@ (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? .li-stx-burn-nft mint request-id amount sender)) (print { type: "burn-request", id: request-id, details: request-details }) - (ok { request-id: request-id, status: PENDING }))) + (if (>= (stx-get-balance .lqstx-vault) amount) + (begin + (try! (contract-call? .lqstx-mint-registry transfer vlqstx-amount (as-contract tx-sender) .token-vlqstx)) + (try! (contract-call? .token-vlqstx burn vlqstx-amount (as-contract tx-sender))) + (try! (contract-call? .token-lqstx dao-burn amount (as-contract tx-sender))) + (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: vlqstx-amount, recipient: sender })))) + (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))) + (ok {request-id: request-id, status: FINALIZED }) + ) + (begin + (try! (contract-call? .li-stx-burn-nft mint request-id amount sender)) + (ok { request-id: request-id, status: PENDING }))))) (define-public (finalize-burn (request-id uint)) (let ( diff --git a/contracts/rules/rebase-1.clar b/contracts/rules/rebase-1.clar index ca16bca..00b0fb9 100644 --- a/contracts/rules/rebase-1.clar +++ b/contracts/rules/rebase-1.clar @@ -26,9 +26,6 @@ (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-02 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)))) + (sender tx-sender)) + (try! (contract-call? .token-lqstx transfer amount sender (as-contract tx-sender) none)) + (as-contract (contract-call? .lqstx-mint-endpoint-v1-02 request-burn sender amount)))) diff --git a/tests/listx-nft.test.ts b/tests/listx-nft.test.ts index 1e81f94..ec8848c 100644 --- a/tests/listx-nft.test.ts +++ b/tests/listx-nft.test.ts @@ -84,7 +84,7 @@ describe('LiSTX NFT', () => { expect(response.result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(2), status: Cl.bufferFromHex('01') }) ); - // nft was already burnt + // nfts were never minted expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-owner', [Cl.uint(1)], user).result).toBeOk( Cl.none() ); @@ -92,7 +92,7 @@ describe('LiSTX NFT', () => { Cl.none() ); expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-last-token-id', [], user).result).toBeOk( - Cl.uint(2) + Cl.uint(0) ); // check that bot received stx diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts index 77778d2..9d73d5c 100644 --- a/tests/lqstx-mint-endpoint.test.ts +++ b/tests/lqstx-mint-endpoint.test.ts @@ -174,8 +174,10 @@ describe(contracts.endpoint, () => { expect(response.result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.buffer(new Uint8Array([1])) }) ); - expect(response.events[7].event).toBe('nft_mint_event'); - expect(response.events[17].event).toBe('nft_burn_event'); + // no nft minted + expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-last-token-id', [], user).result).toBeOk( + Cl.uint(0) + ); }); it('can interact with strategies', () => { From d3028d3b9683a45ff9139eb9a79c362d28d2b55f Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Sun, 24 Mar 2024 10:14:11 +0800 Subject: [PATCH 29/32] working --- Clarinet.toml | 12 - .../deployed/lqstx-mint-endpoint-v1-01.clar | 2 +- contracts/deployed/lqstx-mint-endpoint.clar | 4 +- contracts/extensions/lisa-rebase.clar | 22 -- contracts/extensions/lqstx-mint-endpoint.clar | 158 +++++---- contracts/mocks/rebase-mock.clar | 35 -- contracts/regtest-boot.clar | 19 +- contracts/rules/rebase-1.clar | 31 -- contracts/simnet-boot.clar | 36 +- .../public-pools/fastpool-member.clar | 4 +- .../public-pools/xverse-member.clar | 4 +- deployments/default.simnet-plan.yaml | 35 +- tests/clients/mock-client.ts | 35 +- tests/listx-nft.test.ts | 5 +- ...tx-mint-endpoint-with-public-pools.test.ts | 210 ++++------- tests/lqstx-mint-endpoint.test.ts | 326 ------------------ tests/tokens.test.ts | 2 +- 17 files changed, 218 insertions(+), 722 deletions(-) delete mode 100644 contracts/extensions/lisa-rebase.clar delete mode 100644 contracts/mocks/rebase-mock.clar delete mode 100644 contracts/rules/rebase-1.clar delete mode 100644 tests/lqstx-mint-endpoint.test.ts diff --git a/Clarinet.toml b/Clarinet.toml index d760b64..eb7a72e 100644 --- a/Clarinet.toml +++ b/Clarinet.toml @@ -229,26 +229,14 @@ epoch = 2.4 path = "contracts/deployed/lisa-rebase.clar" epoch = 2.4 -[contracts.lisa-rebase-v1-02] -path = "contracts/extensions/lisa-rebase.clar" -epoch = 2.4 - [contracts.rebase-1] path = "contracts/deployed/rebase-1.clar" epoch = 2.4 -[contracts.rebase-1-v1-02] -path = "contracts/rules/rebase-1.clar" -epoch = 2.4 - [contracts.operators] path = "contracts/extensions/operators.clar" epoch = 2.4 -[contracts.rebase-mock] -path = "contracts/mocks/rebase-mock.clar" -epoch = 2.4 - [contracts.mock-strategy] path = "contracts/mocks/mock-strategy.clar" epoch = 2.4 diff --git a/contracts/deployed/lqstx-mint-endpoint-v1-01.clar b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar index ac84ab8..e0a872b 100644 --- a/contracts/deployed/lqstx-mint-endpoint-v1-01.clar +++ b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar @@ -26,7 +26,7 @@ (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts ;; __IF_MAINNET__ -(define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) +(define-constant pox-info (unwrap-panic (contract-call? 'ST000000000000000000002AMW42H.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) (define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) diff --git a/contracts/deployed/lqstx-mint-endpoint.clar b/contracts/deployed/lqstx-mint-endpoint.clar index c4cdf1f..735bc73 100644 --- a/contracts/deployed/lqstx-mint-endpoint.clar +++ b/contracts/deployed/lqstx-mint-endpoint.clar @@ -83,14 +83,14 @@ ;; @dev used for testing only (define-read-only (get-reward-cycle (stacks-height uint)) - ;; (some (contract-call? 'SP000000000000000000002Q6VF78.pox-3 current-pox-reward-cycle))) + ;; (some (contract-call? 'ST000000000000000000002AMW42H.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)) + ;; (contract-call? 'ST000000000000000000002AMW42H.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) diff --git a/contracts/extensions/lisa-rebase.clar b/contracts/extensions/lisa-rebase.clar deleted file mode 100644 index db74bcf..0000000 --- a/contracts/extensions/lisa-rebase.clar +++ /dev/null @@ -1,22 +0,0 @@ - -;; SPDX-License-Identifier: BUSL-1.1 - -(use-trait strategy-trait .strategy-trait.strategy-trait) - -(define-constant err-unauthorised (err u3000)) - -(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-private (sum-strategy-amounts (strategy ) (accumulator (response uint uint))) - (ok (+ (try! (contract-call? strategy get-amount-in-strategy)) (try! accumulator))) -) - -(define-public (rebase (strategies (list 20 ))) - (let ((total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts strategies (ok u0)))) (contract-call? .lqstx-mint-endpoint-v1-02 get-mint-requests-pending-amount)))) - (try! (is-dao-or-extension)) - (as-contract (try! (contract-call? .token-lqstx set-reserve total-stx))) - (ok total-stx) - ) -) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 78c494a..7e18308 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -5,6 +5,8 @@ ;; lqstx-mint-endpoint-v1-02 ;; +(use-trait strategy-trait .strategy-trait.strategy-trait) + ;; __IF_MAINNET__ (use-trait sip-010-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait) ;; (use-trait sip-010-trait .sip-010-trait.sip-010-trait) @@ -27,7 +29,7 @@ ;; __IF_MAINNET__ (define-data-var request-cutoff uint u300) ;; request must be made 300 blocks before prepare stage starts -(define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) +(define-constant pox-info (unwrap-panic (contract-call? 'ST000000000000000000002AMW42H.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) (define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) @@ -119,10 +121,25 @@ ;; public calls +(define-public (rebase) + (let ( + ;; (total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts (list .public-pools-strategy) (ok u0)))) (get-mint-requests-pending-amount)))) + (available-stx (stx-get-balance .lqstx-vault)) + ;; __IF_MAINNET__ + (deployed-stx (unwrap-panic (contract-call? .public-pools-strategy get-amount-in-strategy))) + ;; (deployed-stx (unwrap-panic (contract-call? .mock-strategy get-amount-in-strategy))) + ;; __ENDIF__ + (pending-stx (get-mint-requests-pending-amount)) + (check-stx (asserts! (>= (+ available-stx deployed-stx) pending-stx) (err deployed-stx))) + (total-stx (- (+ available-stx deployed-stx) pending-stx))) + (as-contract (try! (contract-call? .token-lqstx set-reserve total-stx))) + (ok total-stx))) + ;; @dev the requestor stx is held by the contract until mint can be finalized. (define-public (request-mint (amount uint)) - (let ( + (let ( (sender tx-sender) + (rebase-first (try! (rebase))) (cycle (get-request-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)))) @@ -130,12 +147,14 @@ (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? .li-stx-mint-nft mint request-id amount sender)) + ;; (try! (contract-call? .li-stx-mint-nft mint request-id amount sender)) + (try! (rebase)) (print { type: "mint-request", id: request-id, details: request-details }) (ok request-id))) (define-public (revoke-mint (request-id uint)) (let ( + (rebase-first (try! (rebase))) (request-details (try! (get-mint-request-or-fail request-id))) (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) (try! (is-not-paused-or-fail)) @@ -145,23 +164,86 @@ (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)))) (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) + (try! (rebase)) (ok true))) +(define-public (request-burn (amount uint)) + (let ( + (sender tx-sender) + (rebase-first (try! (rebase))) + (cycle (get-request-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-not-paused-or-fail)) + (print { type: "burn-request", id: request-id, details: request-details }) + (if (>= (stx-get-balance .lqstx-vault) amount) + (begin + (as-contract (try! (contract-call? .token-lqstx dao-burn amount sender))) + (as-contract (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: amount, recipient: sender }))))) + (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED })))) + (try! (rebase)) + (ok {request-id: request-id, status: FINALIZED }) + ) + (begin + (try! (contract-call? .token-vlqstx mint amount sender)) + (try! (contract-call? .token-vlqstx transfer vlqstx-amount sender .lqstx-mint-registry none)) + (as-contract (try! (contract-call? .li-stx-burn-nft mint request-id amount sender))) + (try! (rebase)) + (ok { request-id: request-id, status: PENDING }))))) + (define-public (revoke-burn (request-id uint)) (let ( + (rebase-first (try! (rebase))) (request-details (try! (get-burn-request-or-fail request-id))) (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) (lqstx-amount (contract-call? .token-vlqstx get-shares-to-tokens (get wrapped-amount request-details)))) (try! (is-not-paused-or-fail)) (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (asserts! (is-eq tx-sender recipient) 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) recipient none)) - (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED }))) + (as-contract (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) recipient .token-vlqstx))) + (try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) recipient)) + (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED })))) (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) + (try! (rebase)) (ok true))) +(define-public (finalize-mint (request-id uint)) + (let ( + (rebase-first (try! (rebase))) + (request-details (try! (get-mint-request-or-fail request-id))) + (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) + (try! (validate-mint-request request-id)) + (try! (is-not-paused-or-fail)) + (as-contract (try! (contract-call? .token-lqstx dao-mint (get amount request-details) recipient))) + (as-contract (try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: FINALIZED })))) + (as-contract (try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))) + (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) + (try! (rebase)) + (ok true))) + +(define-public (finalize-mint-many (request-ids (list 1000 uint))) + (fold check-err (map finalize-mint request-ids) (ok true))) + +(define-public (finalize-burn (request-id uint)) + (let ( + (rebase-first (try! (rebase))) + (request-details (try! (get-burn-request-or-fail request-id))) + (transfer-vlqstx (as-contract (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) tx-sender .token-vlqstx)))) + (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) + (validation-data (try! (validate-burn-request request-id)))) + (try! (is-not-paused-or-fail)) + (as-contract (try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) tx-sender))) + (as-contract (try! (contract-call? .token-lqstx dao-burn (get vaulted-amount validation-data) tx-sender))) + (as-contract (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get vaulted-amount validation-data), recipient: recipient }))))) + (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED })))) + (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) + (try! (rebase)) + (ok true))) + +(define-public (finalize-burn-many (request-ids (list 1000 uint))) + (fold check-err (map finalize-burn request-ids) (ok true))) + ;; governance calls (define-public (set-use-whitelist (new-use bool)) @@ -196,66 +278,12 @@ ;; privileged calls -(define-public (finalize-mint (request-id uint)) - (let ( - (request-details (try! (get-mint-request-or-fail request-id))) - (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) - (try! (validate-mint-request request-id)) - (try! (is-not-paused-or-fail)) - (try! (is-dao-or-extension)) - (try! (contract-call? .token-lqstx dao-mint (get amount request-details) recipient)) - (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? .li-stx-mint-nft burn request-id)) - (ok true))) - -(define-public (finalize-mint-many (request-ids (list 1000 uint))) - (fold check-err (map finalize-mint request-ids) (ok true))) - -(define-public (request-burn (sender principal) (amount uint)) - (let ( - (cycle (get-request-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-not-paused-or-fail)) - (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)) - (print { type: "burn-request", id: request-id, details: request-details }) - (if (>= (stx-get-balance .lqstx-vault) amount) - (begin - (try! (contract-call? .lqstx-mint-registry transfer vlqstx-amount (as-contract tx-sender) .token-vlqstx)) - (try! (contract-call? .token-vlqstx burn vlqstx-amount (as-contract tx-sender))) - (try! (contract-call? .token-lqstx dao-burn amount (as-contract tx-sender))) - (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: vlqstx-amount, recipient: sender })))) - (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))) - (ok {request-id: request-id, status: FINALIZED }) - ) - (begin - (try! (contract-call? .li-stx-burn-nft mint request-id amount sender)) - (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))) - (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) - (validation-data (try! (validate-burn-request request-id)))) - (try! (is-not-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: recipient })))) - (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))) - (try! (contract-call? .li-stx-burn-nft burn request-id)) - (ok true))) - -(define-public (finalize-burn-many (request-ids (list 1000 uint))) - (fold check-err (map finalize-burn request-ids) (ok true))) - ;; private calls +(define-private (sum-strategy-amounts (strategy ) (accumulator (response uint uint))) + (ok (+ (try! (contract-call? strategy get-amount-in-strategy)) (try! accumulator))) +) + (define-private (check-err (result (response bool uint)) (prior (response bool uint))) (match prior ok-value result diff --git a/contracts/mocks/rebase-mock.clar b/contracts/mocks/rebase-mock.clar deleted file mode 100644 index 3ddce4e..0000000 --- a/contracts/mocks/rebase-mock.clar +++ /dev/null @@ -1,35 +0,0 @@ - -;; SPDX-License-Identifier: BUSL-1.1 - -(define-constant PENDING 0x00) -(define-constant FINALIZED 0x01) -(define-constant REVOKED 0x02) - -(define-public (rebase) - (as-contract (contract-call? .lisa-rebase-v1-02 rebase (list .mock-strategy)))) - -(define-public (finalize-mint (request-id uint)) - (begin - (try! (rebase)) - (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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-02 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-02 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)) \ No newline at end of file diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index d88dc57..7a78bd3 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -6,17 +6,14 @@ (define-public (execute (sender principal)) (begin (try! (contract-call? .lisa-dao set-extensions (list - {extension: .lqstx-mint-endpoint, enabled: false} - {extension: .lqstx-mint-endpoint-v1-02, enabled: true} - {extension: .lisa-rebase-v1-02, enabled: true} - ;; __IF_MAINNET__ - {extension: .rebase-mock, enabled: true} - ;; {extension: .rebase-1-v1-02, enabled: true} - ;; __ENDIF__ - {extension: .rebase-mock, enabled: true} - {extension: .mock-strategy-manager, enabled: true} - {extension: .lqstx-vault, enabled: true} - {extension: .operators, enabled: true} + { extension: .lqstx-mint-endpoint, enabled: false } + { extension: .lqstx-mint-endpoint-v1-02, enabled: true } + { extension: .lqstx-vault, enabled: true } + { extension: .treasury, enabled: true } + { extension: .token-vesting, enabled: true } + { extension: .public-pools-strategy-manager, enabled: true } + { extension: .operators, enabled: true } + { extension: .mock-strategy-manager, enabled: true } ))) ;; Set initial operators diff --git a/contracts/rules/rebase-1.clar b/contracts/rules/rebase-1.clar deleted file mode 100644 index 00b0fb9..0000000 --- a/contracts/rules/rebase-1.clar +++ /dev/null @@ -1,31 +0,0 @@ - -;; SPDX-License-Identifier: BUSL-1.1 - - -(define-constant PENDING 0x00) -(define-constant FINALIZED 0x01) -(define-constant REVOKED 0x02) - -(define-public (rebase) - (contract-call? .lisa-rebase-v1-02 rebase (list .public-pools-strategy)) -) - -(define-public (finalize-mint (request-id uint)) - (begin - (try! (rebase)) - (as-contract (try! (contract-call? .lqstx-mint-endpoint-v1-02 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-02 finalize-burn request-id))) - (try! (rebase)) - (ok true))) - -(define-public (request-burn (amount uint)) - (let ( - (sender tx-sender)) - (try! (contract-call? .token-lqstx transfer amount sender (as-contract tx-sender) none)) - (as-contract (contract-call? .lqstx-mint-endpoint-v1-02 request-burn sender amount)))) diff --git a/contracts/simnet-boot.clar b/contracts/simnet-boot.clar index 9248f98..cb3c755 100644 --- a/contracts/simnet-boot.clar +++ b/contracts/simnet-boot.clar @@ -12,24 +12,17 @@ { extension: .treasury, enabled: true } { extension: .token-vesting, enabled: true } { extension: .public-pools-strategy-manager, enabled: true } - { extension: .lisa-rebase-v1-02, enabled: true } - { extension: .rebase-1-v1-02, enabled: true } { extension: .operators, enabled: true } ))) ;; Set initial operators (try! (contract-call? .operators set-operators (list - ;; three from ALEX - { operator: 'SP3BQ65DRM8DMTYDD5HWMN60EYC0JFS5NC2V5CWW7, enabled: true } - { operator: 'SPHFAXDZVFHMY8YR3P9J7ZCV6N89SBET203ZAY25, enabled: true } - { operator: 'SPSZ26REB731JN8H00TD010S600F4AB4Z8F0JRB7, enabled: true } - ;; three from Ryder/FAST Pool - { operator: 'SP12BFYTH3NJ6N63KE0S50GHSYV0M91NGQND2B704, enabled: true } - { operator: 'SP1ZPTDQ3801C1AYEZ37NJWNDZ3HM60HC2TCFP228, enabled: true } - { operator: 'SPGAB1P3YV109E22KXFJYM63GK0G21BYX50CQ80B, enabled: true } + {operator: tx-sender, enabled: true} + {operator: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM, enabled: true} + {operator: 'ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND, enabled: true} + {operator: 'ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB, enabled: true} ))) - ;; Set operator signal threshold, i.e. 4-of-6 - (try! (contract-call? .operators set-proposal-threshold 4)) + (try! (contract-call? .operators set-proposal-threshold 2)) ;; Set initial strategy managers, sender is the deployer (try! (contract-call? .public-pools-strategy-manager set-authorised-manager sender true)) @@ -38,24 +31,7 @@ (try! (contract-call? .token-lisa dao-mint-many (list { recipient: .treasury, amount: u1000000000000000 } ))) - - ;; Enable whitelist - (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-use-whitelist false)) - (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-whitelisted-many - (list - 'SP3BQ65DRM8DMTYDD5HWMN60EYC0JFS5NC2V5CWW7 - 'SP2VZBR9GCVM33BN0WXA05VJP6QV7CJ3Z3SQKJ5HH - 'SP12BFYTH3NJ6N63KE0S50GHSYV0M91NGQND2B704 - 'SPGAB1P3YV109E22KXFJYM63GK0G21BYX50CQ80B - 'SPFJVM9Y1A4KJ31T8ZBDESZH36YGPDAZ9WXEFC53 - ) - (list - true - true - true - true - true - ))) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-paused false)) (ok true) ) diff --git a/contracts/strategies/public-pools/fastpool-member.clar b/contracts/strategies/public-pools/fastpool-member.clar index 71fda8c..7e5154f 100644 --- a/contracts/strategies/public-pools/fastpool-member.clar +++ b/contracts/strategies/public-pools/fastpool-member.clar @@ -3,7 +3,7 @@ (define-constant err-unauthorised (err u5000)) -(as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 allow-contract-caller 'SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2 none)) +(as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 allow-contract-caller 'SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2 none)) (define-read-only (is-strategy-caller) (ok (asserts! (is-eq contract-caller .public-pools-strategy) err-unauthorised)) @@ -20,7 +20,7 @@ (define-public (revoke-delegate-stx) (begin (try! (is-strategy-caller)) - (match (as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 revoke-delegate-stx)) + (match (as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 revoke-delegate-stx)) ok-val (ok ok-val) err-val (err (to-uint err-val)) ) diff --git a/contracts/strategies/public-pools/xverse-member.clar b/contracts/strategies/public-pools/xverse-member.clar index 48c6cbe..86f4ce1 100644 --- a/contracts/strategies/public-pools/xverse-member.clar +++ b/contracts/strategies/public-pools/xverse-member.clar @@ -8,7 +8,7 @@ { hashbytes: 0x827a04335a9eb22cb46979f180670c8e7ba453b5, version: 0x04 } ) -(as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 allow-contract-caller 'SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2 none)) +(as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 allow-contract-caller 'SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2 none)) (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)) @@ -37,7 +37,7 @@ (define-public (revoke-delegate-stx) (begin (try! (is-strategy-caller)) - (match (as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 revoke-delegate-stx)) + (match (as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 revoke-delegate-stx)) ok-val (ok ok-val) err-val (err (to-uint err-val)) ) diff --git a/deployments/default.simnet-plan.yaml b/deployments/default.simnet-plan.yaml index 1311056..4b3dd46 100644 --- a/deployments/default.simnet-plan.yaml +++ b/deployments/default.simnet-plan.yaml @@ -305,6 +305,11 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/boot.clar clarity-version: 2 + - emulated-contract-publish: + contract-name: commission-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/traits/commission-trait.clar + clarity-version: 2 - emulated-contract-publish: contract-name: li-stx-burn-nft emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -320,16 +325,6 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/deployed/lisa-rebase.clar clarity-version: 2 - - emulated-contract-publish: - contract-name: lqstx-mint-endpoint-v1-02 - emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM - path: contracts/extensions/lqstx-mint-endpoint.clar - clarity-version: 2 - - emulated-contract-publish: - contract-name: lisa-rebase-v1-02 - emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM - path: contracts/extensions/lisa-rebase.clar - clarity-version: 2 - emulated-contract-publish: contract-name: lisa-transfer-proxy emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -345,6 +340,11 @@ plan: emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/deployed/lqstx-mint-endpoint.clar clarity-version: 2 + - emulated-contract-publish: + contract-name: lqstx-mint-endpoint-v1-02 + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/extensions/lqstx-mint-endpoint.clar + clarity-version: 2 - emulated-contract-publish: contract-name: lqstx-transfer-proxy emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM @@ -368,21 +368,16 @@ plan: epoch: "2.4" - id: 3 transactions: + - emulated-contract-publish: + contract-name: nft-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/traits/nft-trait.clar + clarity-version: 2 - emulated-contract-publish: contract-name: rebase-1 emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM path: contracts/deployed/rebase-1.clar clarity-version: 2 - - emulated-contract-publish: - contract-name: rebase-1-v1-02 - emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM - path: contracts/rules/rebase-1.clar - clarity-version: 2 - - emulated-contract-publish: - contract-name: rebase-mock - 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 diff --git a/tests/clients/mock-client.ts b/tests/clients/mock-client.ts index f6d73cc..1e82b0f 100644 --- a/tests/clients/mock-client.ts +++ b/tests/clients/mock-client.ts @@ -9,6 +9,7 @@ export const createClientMockSetup = () => { const bot = accounts.get('wallet_3')!; const manager = accounts.get('wallet_4')!; const operator3 = accounts.get('wallet_5')!; + const user2 = accounts.get('wallet_6')!; const contracts = { endpoint: 'lqstx-mint-endpoint-v1-02', @@ -17,14 +18,12 @@ export const createClientMockSetup = () => { lqstx: 'token-lqstx', vlqstx: 'token-vlqstx', wstx: 'token-wstx', - strategy: 'mock-strategy', - rebase: 'lisa-rebase-v1-02', - rebase1: 'rebase-mock', + strategy: 'public-pools-strategy', amm: 'amm-swap-pool-v1-1', wlqstx: 'token-wlqstx', dao: 'lisa-dao', - boot: 'regtest-boot', - manager: 'mock-strategy-manager', + boot: 'simnet-boot', + manager: 'public-pools-strategy-manager', operators: 'operators', proposal: 'mock-proposal', proposal2: 'mock-proposal', @@ -46,13 +45,13 @@ export const createClientMockSetup = () => { simnet.callPublicFn(contracts.endpoint, 'request-mint', [Cl.uint(amount)], user); const requestBurn = (amount: IntegerType) => - simnet.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(amount)], user); - - const createPayload = (amount: IntegerType) => - ( - simnet.callReadOnlyFn(contracts.strategy, 'create-payload', [Cl.uint(amount)], manager) - .result as BufferCV - ).buffer; + simnet.callPublicFn(contracts.endpoint, 'request-burn', [Cl.uint(amount)], user); + + const fundStrategy = (amount: IntegerType) => + simnet.callPublicFn(contracts.manager, 'fund-strategy', [Cl.list([Cl.uint(amount)])], manager); + + const finalizeMint = (requestId: IntegerType) => + simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(requestId)], bot); const getRewardCycle = () => { return ( @@ -97,6 +96,13 @@ export const createClientMockSetup = () => { ); }; + const goToNextRequestCycle = () => { + const cycle = getRequestCycle(); + const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); + + simnet.mineEmptyBlocks(blocksToMine); + }; + const goToNextCycle = () => { const cycle = getRewardCycle(); const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); @@ -115,14 +121,17 @@ export const createClientMockSetup = () => { prepareTest, requestMint, requestBurn, - createPayload, + fundStrategy, + finalizeMint, getRewardCycle, getRequestCycle, getBlocksToStartOfCycle, goToNextCycle, + goToNextRequestCycle, getRequestCutoff, liSTXBalance, user, + user2, oracle, bot, manager, diff --git a/tests/listx-nft.test.ts b/tests/listx-nft.test.ts index ec8848c..f58159d 100644 --- a/tests/listx-nft.test.ts +++ b/tests/listx-nft.test.ts @@ -31,6 +31,7 @@ describe('LiSTX NFT', () => { it('user can transfer nft before finalize mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); let response = requestMint(100e6); + console.log(response.events); expect(response.result).toBeOk(Cl.uint(1)); // transfer nft to bot @@ -39,7 +40,7 @@ describe('LiSTX NFT', () => { // finalize mint goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); // check that bot received liquid stx expect(liSTXBalance(user)).toBeUint(0); @@ -72,7 +73,7 @@ describe('LiSTX NFT', () => { expect(response.result).toBeOk(Cl.uint(1)); goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + response = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); expect(response.result).toBeOk(Cl.bool(true)); // request burn diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index 00bb846..e36a447 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -3,115 +3,37 @@ import { tx } from '@hirosystems/clarinet-sdk'; import { Cl, TupleCV, UIntCV } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; +import { createClientMockSetup } from './clients/mock-client'; -const mintDelay = 432; -const accounts = simnet.getAccounts(); -const user = accounts.get('wallet_1')!; -const oracle = accounts.get('wallet_2')!; -const bot = accounts.get('wallet_3')!; -const manager = accounts.get('deployer')!; -const operator = accounts.get('wallet_4')!; -const user2 = accounts.get('wallet_5')!; - -const contracts = { - endpoint: 'lqstx-mint-endpoint-v1-02', - registry: 'lqstx-mint-registry', - vault: 'lqstx-vault', - lqstx: 'token-lqstx', - vlqstx: 'token-vlqstx', - wstx: 'token-wstx', - strategy: 'public-pools-strategy', - rebase: 'lisa-rebase-v1-02', - rebase1: 'rebase-1-v1-02', - amm: 'amm-swap-pool-v1-1', - wlqstx: 'token-wlqstx', - dao: 'lisa-dao', - boot: 'simnet-boot', - manager: 'public-pools-strategy-manager', - operators: 'operators', - proposal: 'mock-proposal', - burnNft: 'li-stx-burn-nft', -}; - -const prepareTest = () => - simnet.mineBlock([ - tx.callPublicFn( - contracts.dao, - 'construct', - [Cl.contractPrincipal(simnet.deployer, contracts.boot)], - simnet.deployer - ), - ]); - -const getRewardCycle = () => { - return ( - simnet.callReadOnlyFn( - contracts.endpoint, - 'get-reward-cycle', - [Cl.uint(simnet.blockHeight)], - user - ).result as UIntCV - ).value; -}; - -const getBlocksToStartOfCycle = (cycle: bigint) => { - return ( - Number( - ( - simnet.callReadOnlyFn( - contracts.endpoint, - 'get-first-burn-block-in-reward-cycle', - [Cl.uint(cycle)], - user - ).result as UIntCV - ).value - ) - simnet.blockHeight - ); -}; -const goToNextCycle = () => { - const cycle = getRewardCycle(); - const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); - - simnet.mineEmptyBlocks(blocksToMine); -}; +const { contracts, user, user2, oracle, bot, manager, + prepareTest, goToNextCycle, goToNextRequestCycle, + requestMint, requestBurn, fundStrategy, finalizeMint } = createClientMockSetup(); // 1m STX const mintAmount = 1_000_000e6; - -const requestMint = () => - simnet.callPublicFn(contracts.endpoint, 'request-mint', [Cl.uint(mintAmount)], user); - -// lock mintAmount stx and request burn of 1 stx -const requestBurn = () => - simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.list([Cl.uint(mintAmount)])], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(1e6)], user), - ]); +const mintDelay = 432; describe(contracts.endpoint, () => { it('can request mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - const response = requestMint(); + const response = requestMint(mintAmount); expect(response.result).toBeOk(Cl.uint(1)); }); it('can finalize mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); goToNextCycle(); - const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + const finaliseErr = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), ]); expect(responses[0].result).toBeOk(Cl.bool(true)); @@ -121,7 +43,7 @@ describe(contracts.endpoint, () => { it('can revoke mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); let responses = simnet.mineBlock([ tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], bot), @@ -133,7 +55,7 @@ describe(contracts.endpoint, () => { goToNextCycle(); simnet.mineEmptyBlocks(mintDelay + 1); responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeErr(Cl.uint(7007)); }); @@ -141,17 +63,15 @@ describe(contracts.endpoint, () => { it('can request burn', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); + goToNextRequestCycle(); + expect(fundStrategy(mintAmount).result).toBeOk(Cl.uint(mintAmount)); goToNextCycle(); simnet.mineEmptyBlocks(mintDelay + 1); - - const responses = requestBurn(); - expect(responses[0].result).toBeOk(Cl.uint(0)); - expect(responses[1].result).toBeOk(Cl.bool(true)); - expect(responses[2].result).toBeOk(Cl.uint(mintAmount)); - expect(responses[3].result).toBeOk(Cl.uint(mintAmount)); - expect(responses[4].result).toBeOk( + expect(finalizeMint(1).result).toBeOk(Cl.bool(true)); + + expect(requestBurn(mintAmount).result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); }); @@ -159,44 +79,40 @@ describe(contracts.endpoint, () => { it('can finalize burn', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); + + goToNextRequestCycle(); + expect(fundStrategy(mintAmount).result).toBeOk(Cl.uint(mintAmount)); goToNextCycle(); simnet.mineEmptyBlocks(mintDelay + 1); - - const burnResponses = requestBurn(); - expect(burnResponses[0].result).toBeOk(Cl.uint(0)); - expect(burnResponses[1].result).toBeOk(Cl.bool(true)); - expect(burnResponses[2].result).toBeOk(Cl.uint(mintAmount)); - expect(burnResponses[3].result).toBeOk(Cl.uint(mintAmount)); - expect(burnResponses[4].result).toBeOk( + expect(finalizeMint(1).result).toBeOk(Cl.bool(true)); + + expect(requestBurn(mintAmount).result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); const responses = simnet.mineBlock([ tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-burn', [Cl.uint(1)], bot), tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], user), ]); expect(responses[0].result).toBeOk(Cl.uint(1e6)); - expect(responses[1].result).toBeOk(Cl.uint(mintAmount)); - expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(7007)); + expect(responses[1].result).toBeOk(Cl.bool(true)); + expect(responses[2].result).toBeErr(Cl.uint(7007)); }); it('can revoke burn', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); + + goToNextRequestCycle(); + expect(fundStrategy(mintAmount).result).toBeOk(Cl.uint(mintAmount)); goToNextCycle(); simnet.mineEmptyBlocks(mintDelay + 1); - - const burnResponses = requestBurn(); - expect(burnResponses[0].result).toBeOk(Cl.uint(0)); - expect(burnResponses[1].result).toBeOk(Cl.bool(true)); - expect(burnResponses[2].result).toBeOk(Cl.uint(mintAmount)); - expect(burnResponses[3].result).toBeOk(Cl.uint(mintAmount)); - expect(burnResponses[4].result).toBeOk( + expect(finalizeMint(1).result).toBeOk(Cl.bool(true)); + + expect(requestBurn(mintAmount).result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); @@ -204,7 +120,7 @@ describe(contracts.endpoint, () => { tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], bot), tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], user), - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeOk(Cl.uint(1e6)); expect(responses[1].result).toBeErr(Cl.uint(3000)); @@ -215,7 +131,7 @@ describe(contracts.endpoint, () => { it('can interact with strategies', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); const cycle = ( simnet.callReadOnlyFn( @@ -239,7 +155,7 @@ describe(contracts.endpoint, () => { simnet.mineEmptyBlocks(blocksToMine - 100); let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.list([Cl.uint(mintAmount)])], bot), tx.callPublicFn( contracts.manager, @@ -261,15 +177,14 @@ describe(contracts.endpoint, () => { simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(mintAmount)], user), - tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(1e6)], user), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'request-burn', [Cl.uint(mintAmount)], user), + tx.callPublicFn(contracts.endpoint, 'request-burn', [Cl.uint(1e6)], user), + tx.callPublicFn(contracts.endpoint, 'finalize-burn', [Cl.uint(1)], bot), tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], bot), tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-burn', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeOk(Cl.bool(true)); expect(responses[1].result).toBeOk( @@ -280,8 +195,7 @@ describe(contracts.endpoint, () => { expect(responses[4].result).toBeErr(Cl.uint(3000)); // not authorized expect(responses[5].result).toBeOk(Cl.uint(1e6)); // refund 1 stx expect(responses[6].result).toBeOk(Cl.uint(0)); // refund 0 stx - expect(responses[7].result).toBeOk(Cl.uint(mintAmount)); // rebase mintAmount stx - expect(responses[8].result).toBeErr(Cl.uint(7006)); // request pending + expect(responses[7].result).toBeErr(Cl.uint(7006)); // request pending // refund remaining stx after unlock goToNextCycle(); @@ -289,7 +203,7 @@ describe(contracts.endpoint, () => { responses = simnet.mineBlock([ tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-burn', [Cl.uint(1)], bot), ]); expect(responses[0].result).toBeOk(Cl.uint(mintAmount - 1e6)); expect(responses[1].result).toBeOk(Cl.bool(true)); @@ -313,12 +227,12 @@ describe(contracts.endpoint, () => { goToNextCycle(); // go to the next cycle simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay - response = simnet.callPublicFn(contracts.rebase1, 'rebase', [], oracle); + response = simnet.callPublicFn(contracts.endpoint, 'rebase', [], oracle); expect(response.result).toBeOk(Cl.uint(0)); - response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + response = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); expect(response.result).toBeOk(Cl.bool(true)); - response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(2)], bot); + response = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(2)], bot); expect(response.result).toBeOk(Cl.bool(true)); response = simnet.callPublicFn( @@ -350,7 +264,7 @@ describe(contracts.endpoint, () => { ], manager ); - response = simnet.callPublicFn(contracts.rebase1, 'rebase', [], oracle); + response = simnet.callPublicFn(contracts.endpoint, 'rebase', [], oracle); expect(response.result).toBeOk(Cl.uint(100_000_100e6)); response = simnet.callReadOnlyFn( @@ -375,7 +289,7 @@ describe(contracts.endpoint, () => { response = simnet.transferSTX(1_000_000e6, `${simnet.deployer}.fastpool-member3`, oracle); response = simnet.transferSTX(1_000_000e6, `${simnet.deployer}.fastpool-member4`, oracle); - response = simnet.callPublicFn(contracts.rebase1, 'rebase', [], oracle); + response = simnet.callPublicFn(contracts.endpoint, 'rebase', [], oracle); expect(response.result).toBeOk(Cl.uint(104_000_100e6)); response = simnet.callReadOnlyFn( @@ -398,17 +312,17 @@ describe(contracts.endpoint, () => { it('can set up amm pool', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); goToNextCycle(); // go to the next cycle - const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + const finaliseErr = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); expect(finaliseErr.result).toBeErr(Cl.uint(7006)); simnet.mineEmptyBlocks(mintDelay + 1); // mint-delay let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), + tx.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot), tx.callPublicFn( contracts.amm, 'create-pool', @@ -432,15 +346,17 @@ describe(contracts.endpoint, () => { let response; // request and finalize mint for 1m STX - response = requestMint(); - expect(response.result).toBeOk(Cl.uint(1)); - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(response.result).toBeOk(Cl.bool(true)); + expect(requestMint(mintAmount).result).toBeOk(Cl.uint(1)); - // request burn - requestBurn(); + goToNextRequestCycle(); + expect(fundStrategy(mintAmount).result).toBeOk(Cl.uint(mintAmount)); + goToNextCycle(); + simnet.mineEmptyBlocks(mintDelay + 1); + expect(finalizeMint(1).result).toBeOk(Cl.bool(true)); + + expect(requestBurn(1e6).result).toBeOk( + Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) + ); // transfer burn of 1 stx response = simnet.callPublicFn( @@ -456,7 +372,7 @@ describe(contracts.endpoint, () => { ); simnet.callPublicFn(contracts.manager, 'refund-strategy', [Cl.list([Cl.bool(true)])], manager), - (response = simnet.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot)); + (response = simnet.callPublicFn(contracts.endpoint, 'finalize-burn', [Cl.uint(1)], bot)); expect(response.result).toBeOk(Cl.bool(true)); // check that bot received stx diff --git a/tests/lqstx-mint-endpoint.test.ts b/tests/lqstx-mint-endpoint.test.ts deleted file mode 100644 index 9d73d5c..0000000 --- a/tests/lqstx-mint-endpoint.test.ts +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -import { tx } from '@hirosystems/clarinet-sdk'; -import { Cl, TupleCV } from '@stacks/transactions'; -import { describe, expect, it } from 'vitest'; -import { createClientMockSetup } from './clients/mock-client'; - -const { - contracts, - prepareTest, - user, - oracle, - bot, - manager, - requestMint: requestMintLib, - createPayload, - goToNextCycle, - getRequestCycle, - getRewardCycle, - getBlocksToStartOfCycle, -} = createClientMockSetup(); - -const mintDelay = 144; -const requestMint = () => requestMintLib(100e6); - -const requestBurn = (payload: Uint8Array) => - simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.uint(100e6)], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user), - ]); - -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)); - }); - - it('can finalize mint', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - - goToNextCycle(); - - const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(7006)); - - simnet.mineEmptyBlocks(mintDelay); - - let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), - ]); - expect(responses[0].result).toBeOk(Cl.bool(true)); - expect(responses[1].result).toBeErr(Cl.uint(7007)); - }); - - it('can revoke mint', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - - let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.endpoint, 'revoke-mint', [Cl.uint(1)], user), - ]); - expect(responses[0].result).toBeErr(Cl.uint(3000)); - expect(responses[1].result).toBeOk(Cl.bool(true)); - - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); // mint-delay - - responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - ]); - expect(responses[0].result).toBeErr(Cl.uint(7007)); - }); - - it('can request burn', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - - const payload = createPayload(100e6); - const responses = requestBurn(payload); - expect(responses[0].result).toBeOk(Cl.uint(0)); - expect(responses[1].result).toBeOk(Cl.bool(true)); - expect(responses[2].result).toBeOk(Cl.uint(100e6)); - expect(responses[3].result).toBeOk(Cl.uint(100e6)); - expect(responses[4].result).toBeOk( - Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) - ); - }); - - it('can finalize burn', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - - const payload = createPayload(100e6); - const burnResponses = requestBurn(payload); - expect(burnResponses[0].result).toBeOk(Cl.uint(0)); - expect(burnResponses[1].result).toBeOk(Cl.bool(true)); - expect(burnResponses[2].result).toBeOk(Cl.uint(100e6)); - expect(burnResponses[3].result).toBeOk(Cl.uint(100e6)); - expect(burnResponses[4].result).toBeOk( - Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) - ); - - const responses = simnet.mineBlock([ - tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.uint(100e6)], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], user), - ]); - expect(responses[0].result).toBeOk(Cl.uint(100e6)); - expect(responses[1].result).toBeOk(Cl.uint(100e6)); - expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(7007)); - }); - - it('can revoke burn', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - - const payload = createPayload(100e6); - const burnResponses = requestBurn(payload); - expect(burnResponses[0].result).toBeOk(Cl.uint(0)); - expect(burnResponses[1].result).toBeOk(Cl.bool(true)); - expect(burnResponses[2].result).toBeOk(Cl.uint(100e6)); - expect(burnResponses[3].result).toBeOk(Cl.uint(100e6)); - expect(burnResponses[4].result).toBeOk( - Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) - ); - - const responses = simnet.mineBlock([ - tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.uint(100e6)], manager), - tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.endpoint, 'revoke-burn', [Cl.uint(1)], user), - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - ]); - expect(responses[0].result).toBeOk(Cl.uint(100e6)); - expect(responses[1].result).toBeErr(Cl.uint(3000)); - expect(responses[2].result).toBeOk(Cl.bool(true)); - expect(responses[3].result).toBeErr(Cl.uint(7007)); - }); - - it('can request burn and finalized immediately', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - expect(requestMint().result).toBeOk(Cl.uint(1)); - - let response; - response = simnet.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user); - expect(response.result).toBeErr(Cl.uint(1)); // not enough funds - - goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - response = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(response.result).toBeOk(Cl.bool(true)); - expect(response.events[2].event).toBe('nft_burn_event'); - response = simnet.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user); - expect(response.result).toBeOk( - Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.buffer(new Uint8Array([1])) }) - ); - // no nft minted - expect(simnet.callReadOnlyFn(contracts.burnNft, 'get-last-token-id', [], user).result).toBeOk( - Cl.uint(0) - ); - }); - - it('can interact with strategies', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - - const cycle = getRewardCycle(); - const blocksToMine = getBlocksToStartOfCycle(cycle + 1n); - simnet.mineEmptyBlocks(blocksToMine - 100); - - let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.uint(100e6)], bot), - tx.callPublicFn(contracts.manager, 'fund-strategy', [Cl.uint(100e6)], manager), - ]); - expect(responses[0].result).toBeErr(Cl.uint(7006)); - expect(responses[1].result).toBeErr(Cl.uint(1000)); - expect(responses[2].result).toBeOk(Cl.uint(100e6)); - - simnet.mineEmptyBlocks(99); // go to the next cycle - simnet.mineEmptyBlocks(mintDelay); - - responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.rebase1, 'request-burn', [Cl.uint(100e6)], user), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), - tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.uint(100e6)], bot), - tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.uint(100e6)], manager), - tx.callPublicFn(contracts.manager, 'refund-strategy', [Cl.uint(100e6)], manager), - tx.callPublicFn(contracts.rebase1, 'rebase', [], oracle), - tx.callPublicFn(contracts.rebase1, 'finalize-burn', [Cl.uint(1)], bot), - ]); - expect(responses[0].result).toBeOk(Cl.bool(true)); - expect(responses[1].result).toBeOk( - Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) - ); - expect(responses[2].result).toBeErr(Cl.uint(7006)); - expect(responses[3].result).toBeErr(Cl.uint(1000)); - expect(responses[4].result).toBeOk(Cl.uint(100e6)); - expect(responses[5].result).toBeErr(Cl.uint(1)); - expect(responses[6].result).toBeOk(Cl.uint(100e6)); - expect(responses[7].result).toBeOk(Cl.bool(true)); - }); - - it('can set up amm pool', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(requestMint().result).toBeOk(Cl.uint(1)); - - goToNextCycle(); - - const finaliseErr = simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); - expect(finaliseErr.result).toBeErr(Cl.uint(7006)); - - simnet.mineEmptyBlocks(mintDelay); - - let responses = simnet.mineBlock([ - tx.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot), - tx.callPublicFn( - contracts.amm, - 'create-pool', - [ - Cl.principal(simnet.deployer + '.' + contracts.wstx), - Cl.principal(simnet.deployer + '.' + contracts.wlqstx), - Cl.uint(1e8), - Cl.principal(user), - Cl.uint(1e8), - Cl.uint(1e8), - ], - user - ), - ]); - expect(responses[0].result).toBeOk(Cl.bool(true)); - expect(responses[1].result).toBeOk(Cl.bool(true)); - }); - - it('operator extension works', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - let responses = simnet.mineBlock([ - tx.callPublicFn( - contracts.operators, - 'propose', - [Cl.contractPrincipal(simnet.deployer, contracts.proposal)], - bot - ), - tx.callPublicFn( - contracts.operators, - 'propose', - [Cl.contractPrincipal(simnet.deployer, contracts.proposal)], - simnet.deployer - ), - ]); - expect(responses[0].result).toBeErr(Cl.uint(1001)); - expect(responses[1].result).toBeOk(Cl.bool(false)); - - responses = simnet.mineBlock([ - tx.callPublicFn( - contracts.operators, - 'signal', - [Cl.contractPrincipal(simnet.deployer, contracts.proposal), Cl.bool(true)], - bot - ), - tx.callPublicFn( - contracts.operators, - 'signal', - [Cl.contractPrincipal(simnet.deployer, contracts.proposal), Cl.bool(true)], - manager - ), - ]); - expect(responses[0].result).toBeErr(Cl.uint(1001)); - expect(responses[1].result).toBeOk(Cl.bool(true)); - }); - - it('request cycle respects cutoff', () => { - prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); - - expect(getRequestCycle()).toBe(0n); - // cycle length - prepare cycle length - cutoff - blocks for deployment and prepare - simnet.mineEmptyBlocks(1050 - 50 - 300 - 6); - // we are at the end of request cycle 0 - expect(simnet.blockHeight).toBe(699); - expect(getRequestCycle()).toBe(0n); - - simnet.mineEmptyBlocks(1050); // cycle length - // we are at end of request cycle 1 - expect(simnet.blockHeight).toBe(1749); - expect(getRequestCycle()).toBe(1n); - - simnet.mineEmptyBlocks(1); - // we are at beginning of request cycle 2 - // that is 1050 + 1050 - 50 - 100 - expect(simnet.blockHeight).toBe(1750); - expect(getRequestCycle()).toBe(2n); - - const response = requestMint(); - expect(response.result).toBeOk(Cl.uint(1)); - expect(response.events[0].event).toBe('stx_transfer_event'); - expect(response.events[1].event).toBe('nft_mint_event'); - expect(response.events[2].event).toBe('print_event'); - expect( - ((response.events[2].data.value as TupleCV).data.details as TupleCV).data['requested-at'] - ).toBeUint(2); - }); -}); diff --git a/tests/tokens.test.ts b/tests/tokens.test.ts index dfdb754..3760989 100644 --- a/tests/tokens.test.ts +++ b/tests/tokens.test.ts @@ -11,7 +11,7 @@ describe('lisa token', () => { requestMint(100e6); goToNextCycle(); simnet.mineEmptyBlocks(mintDelay); - simnet.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); }); sip10Tests(contracts.lqstx); From b048e18781221e91486d54c7d9211062b29ba251 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Sun, 24 Mar 2024 11:08:28 +0800 Subject: [PATCH 30/32] moved lisa-rebase/rebase-1 into lqstx-mint-endpoint --- README.md | 1 - .../deployed/lqstx-mint-endpoint-v1-01.clar | 2 +- contracts/deployed/lqstx-mint-endpoint.clar | 4 +- contracts/extensions/lqstx-mint-endpoint.clar | 44 +++++++++---------- contracts/simnet-boot.clar | 10 +++-- .../public-pools/fastpool-member.clar | 4 +- .../public-pools/xverse-member.clar | 4 +- package.json | 2 +- scripts/error-codes.ts | 1 + tests/clients/mock-client.ts | 2 +- tests/listx-nft.test.ts | 15 ++++--- ...tx-mint-endpoint-with-public-pools.test.ts | 3 +- tests/tokens.test.ts | 12 +++-- 13 files changed, 56 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 1034166..286842c 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,6 @@ are in the form `(err uint)` and they are unique across all contracts. | li-stx-burn-nft | err-unauthorised | (err u3000) | | | li-stx-mint-nft | err-unauthorised | (err u3000) | | | lisa-rebase | err-unauthorised | (err u3000) | | -| lisa-rebase-v1-02 | err-unauthorised | (err u3000) | | | lqstx-mint-endpoint-v1-02 | err-unauthorised | (err u3000) | | | public-pools-strategy-manager | err-unauthorised | (err u3000) | | | token-lisa | err-unauthorised | (err u3000) | | diff --git a/contracts/deployed/lqstx-mint-endpoint-v1-01.clar b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar index e0a872b..ac84ab8 100644 --- a/contracts/deployed/lqstx-mint-endpoint-v1-01.clar +++ b/contracts/deployed/lqstx-mint-endpoint-v1-01.clar @@ -26,7 +26,7 @@ (define-data-var mint-delay uint u432) ;; mint available 3 day after cycle starts ;; __IF_MAINNET__ -(define-constant pox-info (unwrap-panic (contract-call? 'ST000000000000000000002AMW42H.pox-3 get-pox-info))) +(define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) (define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) diff --git a/contracts/deployed/lqstx-mint-endpoint.clar b/contracts/deployed/lqstx-mint-endpoint.clar index 735bc73..c4cdf1f 100644 --- a/contracts/deployed/lqstx-mint-endpoint.clar +++ b/contracts/deployed/lqstx-mint-endpoint.clar @@ -83,14 +83,14 @@ ;; @dev used for testing only (define-read-only (get-reward-cycle (stacks-height uint)) - ;; (some (contract-call? 'ST000000000000000000002AMW42H.pox-3 current-pox-reward-cycle))) + ;; (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? 'ST000000000000000000002AMW42H.pox-3 reward-cycle-to-burn-height reward-cycle)) + ;; (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) diff --git a/contracts/extensions/lqstx-mint-endpoint.clar b/contracts/extensions/lqstx-mint-endpoint.clar index 7e18308..ad313da 100644 --- a/contracts/extensions/lqstx-mint-endpoint.clar +++ b/contracts/extensions/lqstx-mint-endpoint.clar @@ -29,7 +29,7 @@ ;; __IF_MAINNET__ (define-data-var request-cutoff uint u300) ;; request must be made 300 blocks before prepare stage starts -(define-constant pox-info (unwrap-panic (contract-call? 'ST000000000000000000002AMW42H.pox-3 get-pox-info))) +(define-constant pox-info (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.pox-3 get-pox-info))) (define-constant activation-burn-block (get first-burnchain-block-height pox-info)) (define-constant reward-cycle-length (get reward-cycle-length pox-info)) (define-constant prepare-cycle-length (get prepare-cycle-length pox-info)) @@ -123,16 +123,14 @@ (define-public (rebase) (let ( - ;; (total-stx (- (+ (stx-get-balance .lqstx-vault) (try! (fold sum-strategy-amounts (list .public-pools-strategy) (ok u0)))) (get-mint-requests-pending-amount)))) (available-stx (stx-get-balance .lqstx-vault)) ;; __IF_MAINNET__ (deployed-stx (unwrap-panic (contract-call? .public-pools-strategy get-amount-in-strategy))) ;; (deployed-stx (unwrap-panic (contract-call? .mock-strategy get-amount-in-strategy))) ;; __ENDIF__ (pending-stx (get-mint-requests-pending-amount)) - (check-stx (asserts! (>= (+ available-stx deployed-stx) pending-stx) (err deployed-stx))) (total-stx (- (+ available-stx deployed-stx) pending-stx))) - (as-contract (try! (contract-call? .token-lqstx set-reserve total-stx))) + (try! (contract-call? .token-lqstx set-reserve total-stx)) (ok total-stx))) ;; @dev the requestor stx is held by the contract until mint can be finalized. @@ -147,7 +145,7 @@ (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? .li-stx-mint-nft mint request-id amount sender)) + (try! (contract-call? .li-stx-mint-nft mint request-id amount sender)) (try! (rebase)) (print { type: "mint-request", id: request-id, details: request-details }) (ok request-id))) @@ -163,7 +161,7 @@ (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get amount request-details), recipient: recipient })))) (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)))) - (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) + (try! (contract-call? .li-stx-mint-nft burn request-id)) (try! (rebase)) (ok true))) @@ -179,16 +177,16 @@ (print { type: "burn-request", id: request-id, details: request-details }) (if (>= (stx-get-balance .lqstx-vault) amount) (begin - (as-contract (try! (contract-call? .token-lqstx dao-burn amount sender))) - (as-contract (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: amount, recipient: sender }))))) - (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED })))) + (try! (contract-call? .token-lqstx dao-burn amount sender)) + (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: amount, recipient: sender })))) + (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))) (try! (rebase)) (ok {request-id: request-id, status: FINALIZED }) ) (begin (try! (contract-call? .token-vlqstx mint amount sender)) (try! (contract-call? .token-vlqstx transfer vlqstx-amount sender .lqstx-mint-registry none)) - (as-contract (try! (contract-call? .li-stx-burn-nft mint request-id amount sender))) + (try! (contract-call? .li-stx-burn-nft mint request-id amount sender)) (try! (rebase)) (ok { request-id: request-id, status: PENDING }))))) @@ -201,10 +199,10 @@ (try! (is-not-paused-or-fail)) (asserts! (is-eq PENDING (get status request-details)) err-request-finalized-or-revoked) (asserts! (is-eq tx-sender recipient) err-unauthorised) - (as-contract (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) recipient .token-vlqstx))) + (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) recipient .token-vlqstx)) (try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) recipient)) - (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED })))) - (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) + (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: REVOKED }))) + (try! (contract-call? .li-stx-burn-nft burn request-id)) (try! (rebase)) (ok true))) @@ -215,10 +213,10 @@ (recipient (unwrap! (unwrap-panic (get-owner-mint-nft request-id)) err-request-finalized-or-revoked))) (try! (validate-mint-request request-id)) (try! (is-not-paused-or-fail)) - (as-contract (try! (contract-call? .token-lqstx dao-mint (get amount request-details) recipient))) - (as-contract (try! (contract-call? .lqstx-mint-registry set-mint-request request-id (merge request-details { status: FINALIZED })))) - (as-contract (try! (contract-call? .lqstx-mint-registry set-mint-requests-pending-amount (- (get-mint-requests-pending-amount) (get amount request-details))))) - (as-contract (try! (contract-call? .li-stx-mint-nft burn request-id))) + (try! (contract-call? .token-lqstx dao-mint (get amount request-details) recipient)) + (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? .li-stx-mint-nft burn request-id)) (try! (rebase)) (ok true))) @@ -229,15 +227,15 @@ (let ( (rebase-first (try! (rebase))) (request-details (try! (get-burn-request-or-fail request-id))) - (transfer-vlqstx (as-contract (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) tx-sender .token-vlqstx)))) + (transfer-vlqstx (try! (contract-call? .lqstx-mint-registry transfer (get wrapped-amount request-details) (as-contract tx-sender) .token-vlqstx))) (recipient (unwrap! (unwrap-panic (get-owner-burn-nft request-id)) err-request-finalized-or-revoked)) (validation-data (try! (validate-burn-request request-id)))) (try! (is-not-paused-or-fail)) - (as-contract (try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) tx-sender))) - (as-contract (try! (contract-call? .token-lqstx dao-burn (get vaulted-amount validation-data) tx-sender))) - (as-contract (try! (contract-call? .lqstx-vault proxy-call .stx-transfer-proxy (unwrap-panic (to-consensus-buff? { ustx: (get vaulted-amount validation-data), recipient: recipient }))))) - (as-contract (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED })))) - (as-contract (try! (contract-call? .li-stx-burn-nft burn request-id))) + (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: recipient })))) + (try! (contract-call? .lqstx-mint-registry set-burn-request request-id (merge request-details { status: FINALIZED }))) + (try! (contract-call? .li-stx-burn-nft burn request-id)) (try! (rebase)) (ok true))) diff --git a/contracts/simnet-boot.clar b/contracts/simnet-boot.clar index cb3c755..6b8ec06 100644 --- a/contracts/simnet-boot.clar +++ b/contracts/simnet-boot.clar @@ -24,14 +24,16 @@ ))) (try! (contract-call? .operators set-proposal-threshold 2)) - ;; Set initial strategy managers, sender is the deployer - (try! (contract-call? .public-pools-strategy-manager set-authorised-manager sender true)) - ;; Mint max LISA token supply (1bn) (try! (contract-call? .token-lisa dao-mint-many (list { recipient: .treasury, amount: u1000000000000000 } ))) - + + ;; Set initial strategy managers, sender is the deployer + (try! (contract-call? .public-pools-strategy-manager set-authorised-manager sender true)) + (try! (contract-call? .public-pools-strategy-manager set-authorised-manager 'ST2QXSK64YQX3CQPC530K79XWQ98XFAM9W3XKEH3N true)) + (try! (contract-call? .public-pools-strategy-manager set-authorised-manager 'ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND true)) + (try! (contract-call? .lqstx-mint-endpoint-v1-02 set-paused false)) (ok true) ) diff --git a/contracts/strategies/public-pools/fastpool-member.clar b/contracts/strategies/public-pools/fastpool-member.clar index 7e5154f..71fda8c 100644 --- a/contracts/strategies/public-pools/fastpool-member.clar +++ b/contracts/strategies/public-pools/fastpool-member.clar @@ -3,7 +3,7 @@ (define-constant err-unauthorised (err u5000)) -(as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 allow-contract-caller 'SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2 none)) +(as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 allow-contract-caller 'SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2 none)) (define-read-only (is-strategy-caller) (ok (asserts! (is-eq contract-caller .public-pools-strategy) err-unauthorised)) @@ -20,7 +20,7 @@ (define-public (revoke-delegate-stx) (begin (try! (is-strategy-caller)) - (match (as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 revoke-delegate-stx)) + (match (as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 revoke-delegate-stx)) ok-val (ok ok-val) err-val (err (to-uint err-val)) ) diff --git a/contracts/strategies/public-pools/xverse-member.clar b/contracts/strategies/public-pools/xverse-member.clar index 86f4ce1..48c6cbe 100644 --- a/contracts/strategies/public-pools/xverse-member.clar +++ b/contracts/strategies/public-pools/xverse-member.clar @@ -8,7 +8,7 @@ { hashbytes: 0x827a04335a9eb22cb46979f180670c8e7ba453b5, version: 0x04 } ) -(as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 allow-contract-caller 'SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2 none)) +(as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 allow-contract-caller 'SP001SFSMC2ZY76PD4M68P3WGX154XCH7NE3TYMX.pox-pools-1-cycle-v2 none)) (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)) @@ -37,7 +37,7 @@ (define-public (revoke-delegate-stx) (begin (try! (is-strategy-caller)) - (match (as-contract (contract-call? 'ST000000000000000000002AMW42H.pox-3 revoke-delegate-stx)) + (match (as-contract (contract-call? 'SP000000000000000000002Q6VF78.pox-3 revoke-delegate-stx)) ok-val (ok ok-val) err-val (err (to-uint err-val)) ) diff --git a/package.json b/package.json index 3324cb3..32f7892 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "multisig-analyse": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/analyse-multisig-deployment-plan.ts", "get-keys": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/get-secret-pubkeys.ts", "generate-secret": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/generate-secret.ts", - "error-codes": "node --no-warnings=ExperimentalWarning --loader ts-node/esm --import=./scripts/logErrors.js ./scripts/error-codes.ts", + "error-codes": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/error-codes.ts", "replace:mainnet": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/replace-mainnet-address.ts", "replace:testnet": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/replace-testnet-address.ts", "setup:clarity": "./scripts/clarinet_manager.sh clean && ./scripts/clarinet_manager.sh install", diff --git a/scripts/error-codes.ts b/scripts/error-codes.ts index 1dfdc55..8b5c23b 100644 --- a/scripts/error-codes.ts +++ b/scripts/error-codes.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import { initSimnet } from '@hirosystems/clarinet-sdk'; import { createErrorsTable } from './lib/error-codes.ts'; + const manifestFile = './Clarinet.toml'; const simnet = await initSimnet(manifestFile); diff --git a/tests/clients/mock-client.ts b/tests/clients/mock-client.ts index 1e82b0f..1e78fb5 100644 --- a/tests/clients/mock-client.ts +++ b/tests/clients/mock-client.ts @@ -1,6 +1,6 @@ import { tx } from '@hirosystems/clarinet-sdk'; import { IntegerType } from '@stacks/common'; -import { BufferCV, Cl, ResponseOkCV, UIntCV } from '@stacks/transactions'; +import { Cl, ResponseOkCV, UIntCV } from '@stacks/transactions'; export const createClientMockSetup = () => { const accounts = simnet.getAccounts(); diff --git a/tests/listx-nft.test.ts b/tests/listx-nft.test.ts index f58159d..85cae31 100644 --- a/tests/listx-nft.test.ts +++ b/tests/listx-nft.test.ts @@ -4,7 +4,7 @@ import { Cl } from '@stacks/transactions'; import { describe, expect, it } from 'vitest'; import { createClientMockSetup } from './clients/mock-client'; -const { contracts, prepareTest, requestMint, requestBurn, goToNextCycle, liSTXBalance, user, bot } = +const { contracts, prepareTest, requestMint, requestBurn, goToNextCycle, liSTXBalance, goToNextRequestCycle, fundStrategy, user, bot } = createClientMockSetup(); const mintDelay = 14; @@ -31,15 +31,16 @@ describe('LiSTX NFT', () => { it('user can transfer nft before finalize mint', () => { prepareTest().map((e: any) => expect(e.result).toBeOk(Cl.bool(true))); let response = requestMint(100e6); - console.log(response.events); expect(response.result).toBeOk(Cl.uint(1)); // transfer nft to bot response = transferMintNFT(1, bot); expect(response.result).toBeOk(Cl.bool(true)); // finalize mint + goToNextRequestCycle(); + expect(fundStrategy(100e6).result).toBeOk(Cl.uint(100e6)); goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); + simnet.mineEmptyBlocks(mintDelay + 1); simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); // check that bot received liquid stx @@ -71,8 +72,10 @@ describe('LiSTX NFT', () => { // request and finalize mint response = requestMint(100e6); expect(response.result).toBeOk(Cl.uint(1)); + goToNextRequestCycle(); + expect(fundStrategy(1e6).result).toBeOk(Cl.uint(1e6)); goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); + simnet.mineEmptyBlocks(mintDelay + 1); response = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); expect(response.result).toBeOk(Cl.bool(true)); @@ -81,7 +84,7 @@ describe('LiSTX NFT', () => { expect(response.result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('01') }) ); - response = requestBurn(40e6); + response = requestBurn(39e6); expect(response.result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(2), status: Cl.bufferFromHex('01') }) ); @@ -98,6 +101,6 @@ describe('LiSTX NFT', () => { // check that bot received stx expect(simnet.getAssetsMap().get('STX')?.get(bot)).toBe(100000000000000n); - expect(simnet.getAssetsMap().get('STX')?.get(user)).toBe(100000000000000n); + expect(simnet.getAssetsMap().get('STX')?.get(user)).toBe(99999999000000n); }); }); diff --git a/tests/lqstx-mint-endpoint-with-public-pools.test.ts b/tests/lqstx-mint-endpoint-with-public-pools.test.ts index e36a447..abd3eaf 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -11,6 +11,7 @@ const { contracts, user, user2, oracle, bot, manager, // 1m STX const mintAmount = 1_000_000e6; + const mintDelay = 432; describe(contracts.endpoint, () => { @@ -87,7 +88,7 @@ describe(contracts.endpoint, () => { simnet.mineEmptyBlocks(mintDelay + 1); expect(finalizeMint(1).result).toBeOk(Cl.bool(true)); - expect(requestBurn(mintAmount).result).toBeOk( + expect(requestBurn(1e6).result).toBeOk( Cl.tuple({ 'request-id': Cl.uint(1), status: Cl.bufferFromHex('00') }) ); diff --git a/tests/tokens.test.ts b/tests/tokens.test.ts index 3760989..e35be5f 100644 --- a/tests/tokens.test.ts +++ b/tests/tokens.test.ts @@ -2,16 +2,20 @@ import { Cl } from '@stacks/transactions'; import { beforeEach, describe, expect } from 'vitest'; import { createClientMockSetup } from './clients/mock-client'; import { sip10Tests } from './clients/sip10-client.ts'; -const { goToNextCycle, requestMint, prepareTest, contracts, bot } = createClientMockSetup(); +const { goToNextCycle, goToNextRequestCycle, fundStrategy, requestMint, prepareTest, contracts, bot } = createClientMockSetup(); const mintDelay = 14; describe('lisa token', () => { beforeEach(() => { prepareTest().map(r => expect(r.result).toBeOk(Cl.bool(true))); - requestMint(100e6); + let response = requestMint(100e6); + expect(response.result).toBeOk(Cl.uint(1)); + goToNextRequestCycle(); + expect(fundStrategy(1e6).result).toBeOk(Cl.uint(1e6)); goToNextCycle(); - simnet.mineEmptyBlocks(mintDelay); - simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); + simnet.mineEmptyBlocks(mintDelay + 1); + response = simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); + expect(response.result).toBeOk(Cl.bool(true)); }); sip10Tests(contracts.lqstx); From efa8317eee47a8981ca50421514445e19c969443 Mon Sep 17 00:00:00 2001 From: fiftyeightandeight Date: Sun, 24 Mar 2024 15:37:00 +0800 Subject: [PATCH 31/32] remove public-pool-strategy-manager from regtest-book --- contracts/regtest-boot.clar | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index 7a78bd3..99f405c 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -10,8 +10,7 @@ { extension: .lqstx-mint-endpoint-v1-02, enabled: true } { extension: .lqstx-vault, enabled: true } { extension: .treasury, enabled: true } - { extension: .token-vesting, enabled: true } - { extension: .public-pools-strategy-manager, enabled: true } + { extension: .token-vesting, enabled: true } { extension: .operators, enabled: true } { extension: .mock-strategy-manager, enabled: true } ))) From 36acb215953c4b5c5dd49763b734574ad5e78fa2 Mon Sep 17 00:00:00 2001 From: Kyle Fang Date: Sun, 24 Mar 2024 15:41:47 +0800 Subject: [PATCH 32/32] feat: update token to be regtest compatible --- contracts/regtest-boot.clar | 5 ++--- contracts/token-lisa.clar | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/contracts/regtest-boot.clar b/contracts/regtest-boot.clar index 7a78bd3..55a3891 100644 --- a/contracts/regtest-boot.clar +++ b/contracts/regtest-boot.clar @@ -7,11 +7,10 @@ (begin (try! (contract-call? .lisa-dao set-extensions (list { extension: .lqstx-mint-endpoint, enabled: false } - { extension: .lqstx-mint-endpoint-v1-02, enabled: true } + { extension: .lqstx-mint-endpoint-v1-02, enabled: true } { extension: .lqstx-vault, enabled: true } { extension: .treasury, enabled: true } - { extension: .token-vesting, enabled: true } - { extension: .public-pools-strategy-manager, enabled: true } + { extension: .token-vesting, enabled: true } { extension: .operators, enabled: true } { extension: .mock-strategy-manager, enabled: true } ))) diff --git a/contracts/token-lisa.clar b/contracts/token-lisa.clar index 9dd4931..9c58d53 100644 --- a/contracts/token-lisa.clar +++ b/contracts/token-lisa.clar @@ -1,7 +1,11 @@ ;; SPDX-License-Identifier: BUSL-1.1 +;; __IF_MAINNET__ (impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait) +;; (impl-trait .sip-010-trait.sip-010-trait) +;; __ENDIF__ + (define-constant err-unauthorised (err u3000)) (define-constant err-not-token-owner (err u4))