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/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/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..ad313da 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) @@ -119,10 +121,23 @@ ;; public calls +(define-public (rebase) + (let ( + (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)) + (total-stx (- (+ available-stx deployed-stx) pending-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. (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)))) @@ -131,11 +146,13 @@ (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! (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)) @@ -144,24 +161,87 @@ (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))) +(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 + (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)) + (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 transfer (get wrapped-amount request-details) recipient .token-vlqstx)) + (try! (contract-call? .token-vlqstx burn (get wrapped-amount request-details) recipient)) (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? .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)) + (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))) + +(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 (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! (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))) + +(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 +276,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..6b8ec06 100644 --- a/contracts/simnet-boot.clar +++ b/contracts/simnet-boot.clar @@ -12,50 +12,28 @@ { 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)) - - ;; Set initial strategy managers, sender is the deployer - (try! (contract-call? .public-pools-strategy-manager set-authorised-manager sender true)) + (try! (contract-call? .operators set-proposal-threshold 2)) ;; Mint max LISA token supply (1bn) (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 - ))) + ;; 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/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/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 f6d73cc..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(); @@ -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..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; @@ -37,9 +37,11 @@ describe('LiSTX NFT', () => { 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.callPublicFn(contracts.rebase1, 'finalize-mint', [Cl.uint(1)], bot); + simnet.mineEmptyBlocks(mintDelay + 1); + simnet.callPublicFn(contracts.endpoint, 'finalize-mint', [Cl.uint(1)], bot); // check that bot received liquid stx expect(liSTXBalance(user)).toBeUint(0); @@ -70,9 +72,11 @@ 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); - response = simnet.callPublicFn(contracts.rebase1, '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)); // request burn @@ -80,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') }) ); @@ -97,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 00bb846..abd3eaf 100644 --- a/tests/lqstx-mint-endpoint-with-public-pools.test.ts +++ b/tests/lqstx-mint-endpoint-with-public-pools.test.ts @@ -3,115 +3,38 @@ 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 +44,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 +56,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 +64,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 +80,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(1e6).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 +121,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 +132,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 +156,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 +178,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 +196,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 +204,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 +228,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 +265,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 +290,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 +313,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 +347,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 +373,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..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.rebase1, '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);