mirror of
https://github.com/zhigang1992/liquid-stacking.git
synced 2026-01-12 17:23:23 +08:00
Merge pull request #33 from alexgo-io/feat/error-codes
Feat/error codes
This commit is contained in:
@@ -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
|
||||
|
||||
15
README.md
15
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. |
|
||||
@@ -34,6 +35,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) | |
|
||||
@@ -57,10 +59,11 @@ 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) | |
|
||||
| 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) | |
|
||||
@@ -113,6 +116,16 @@ 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) | |
|
||||
|
||||
136
contracts/aux/li-stx-burn-nft.clar
Normal file
136
contracts/aux/li-stx-burn-nft.clar
Normal file
@@ -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 <commission-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 <commission-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)))
|
||||
|
||||
136
contracts/aux/li-stx-mint-nft.clar
Normal file
136
contracts/aux/li-stx-mint-nft.clar
Normal file
@@ -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 <commission-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 <commission-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)))
|
||||
|
||||
@@ -125,6 +125,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)))
|
||||
|
||||
@@ -140,6 +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))
|
||||
(ok true)))
|
||||
|
||||
(define-public (revoke-burn (request-id uint))
|
||||
@@ -156,6 +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))
|
||||
(ok true)))
|
||||
|
||||
;; governance calls
|
||||
@@ -203,6 +206,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)))
|
||||
@@ -220,6 +224,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 })))
|
||||
|
||||
@@ -236,6 +241,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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = '<!--errors-->';
|
||||
|
||||
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<Array<string>> = [];
|
||||
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);
|
||||
|
||||
86
scripts/lib/error-codes.ts
Normal file
86
scripts/lib/error-codes.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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 = '<!--errors-->';
|
||||
|
||||
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<Array<string>> = [];
|
||||
const longestColumnCells = tableHeader.map(v => v.length);
|
||||
|
||||
const compareReadme = extractCheck && readme;
|
||||
|
||||
for (const [contractId] of simnet.getContractsInterfaces()) {
|
||||
if (isTestContract(contractId)) continue;
|
||||
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}`);
|
||||
}
|
||||
11
tests/errors.test.ts
Normal file
11
tests/errors.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
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
|
||||
});
|
||||
});
|
||||
@@ -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(
|
||||
|
||||
@@ -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,12 +398,12 @@ 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('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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user