Customizable Wrapper
Explanations
Section titled “Explanations”All actions are stored in a main Smart Contract that the admin checks and performs operations based on what is stored in that moment on the queues.
Errors and constants
Section titled “Errors and constants”(define-constant err-invalid (err u300))(define-constant err-too-many-pending-requests (err u200))(define-constant err-not-owner (err u100))(define-constant err-component-type-invalid (err u501))
(define-constant background-type "background-type")(define-constant car-type "car-type")(define-constant rim-type "rim-type")(define-constant head-type "head-type")(define-constant miami-type "miami")(define-constant nyc-type "nyc")
(define-constant burn-address 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG)Contract owner
Section titled “Contract owner”(define-data-var contract-owner principal tx-sender)Disassemble
Section titled “Disassemble”;; eg. case;;(contract-call? .degens mint-uri 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "uriNiceDegen");; ::set_tx_sender STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract add-disassemble-work-in-queue u1);; ::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract disassemble-finalize u1 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "DarkPurple" "BentleyBlack" "ClassyCream" "Miami_Syringe_Cigar");; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.cars get-token-uri u1);; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.cars get-owner u1)
;; Queue for work(define-data-var disassemble-work-queue (list 100 {member: principal, token-id: uint}) (list))
(define-public (disassemble-finalize (token-id uint) (member principal) (background-name (string-ascii 30)) (car-name (string-ascii 30)) (rim-name (string-ascii 30)) (head-name (string-ascii 30))) (begin ;; Check that admin is calling this contract (asserts! (is-eq tx-sender (var-get contract-owner)) err-invalid) (asserts! (is-eq (some token-id) (get token-id (unwrap-panic (get-disassemble-head-work-queue)))) err-invalid) (unwrap-panic (contract-call? .backgrounds mint-name member background-name)) (unwrap-panic (contract-call? .cars mint-name member car-name)) (unwrap-panic (contract-call? .rims mint-name member rim-name)) (unwrap-panic (contract-call? .heads mint-name member head-name)) (pop-disassemble-work-queue)))
(define-read-only (get-disassemble-work-queue) ;; Get the actual work-queue so that we can process it (ok (var-get disassemble-work-queue)))
(define-read-only (get-disassemble-head-work-queue) ;; Get the first element in the work queue so that we can process it (ok (element-at (var-get disassemble-work-queue) u0)))
(define-public (prepare-disassemble (token-id uint)) (add-disassemble-work-in-queue token-id))
(define-public (add-disassemble-work-in-queue (token-id uint)) (ok (begin ;; check user is owner of nft (asserts! (is-eq (some tx-sender) (unwrap-panic (contract-call? .degens get-owner token-id))) err-not-owner) ;; transfer fees if not contract-owner (if (is-eq tx-sender (var-get contract-owner)) true (try! (fee-processing))) (let ((work-queue-value (var-get disassemble-work-queue)) (value-to-add {token-id: token-id, member: tx-sender})) (var-set disassemble-work-queue (begin ;; check user has not already inserted this ;; if the id is already in the queue that means the NFT is burnt => throws err-not-owner when calling for get-owner ;; (asserts! ;; (is-none (index-of work-queue-value value-to-add)) ;; err-invalid ;; ) ;; check user is not abusing the queue (asserts! (< (len (filter is-disassemble-value-for-principal work-queue-value)) u5) err-too-many-pending-requests) (unwrap-panic (contract-call? .degens burn-token token-id)) (append (unwrap-panic (as-max-len? work-queue-value u99)) value-to-add)))))))
(define-private (pop-disassemble-work-queue) (ok (let ((work-queue-value (var-get disassemble-work-queue))) (var-set disassemble-work-queue ;; Remove first element in list (filter is-disassemble-first-element work-queue-value)))))
(define-private (is-disassemble-first-element (value {token-id: uint, member: principal})) (let ((first-element (element-at (var-get disassemble-work-queue) u0))) (not (and (is-some first-element) (is-eq value (unwrap-panic first-element))))))
;; Helper functions(define-private (is-disassemble-value-for-principal (value {token-id: uint, member: principal})) (is-eq (get member value) tx-sender)Assemble
Section titled “Assemble”;; eg. case;; (contract-call? .backgrounds mint-name 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "DarkPurple");; (contract-call? .cars mint-name 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "BentleyBlack");; (contract-call? .rims mint-name 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "ClassyCream");; (contract-call? .heads mint-name 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "NYC_Antenna_BigSmile");; ::set_tx_sender STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract add-assemble-work-in-queue u1 u1 u1 u1);; ::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM;; (contract-call? .upgrade-contract assemble-finalize 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "uri-custom")
(define-data-var assemble-work-queue (list 100 {member: principal, background-id: uint, car-id: uint, rim-id: uint, head-id: uint}) (list))
(define-public (assemble-finalize (member principal) (metadata-uri (string-ascii 99))) (begin ;; Check that admin is calling this contract (asserts! (is-eq tx-sender (var-get contract-owner)) err-invalid) (unwrap-panic (contract-call? .degens mint-uri member metadata-uri)) (pop-assemble-work-queue)))
(define-read-only (get-assemble-work-queue) ;; Get the actual work-queue so that we can process it (ok (var-get assemble-work-queue)))
(define-read-only (get-assemble-head-work-queue) ;; Get the first element in the work queue so that we can process it (ok (element-at (var-get assemble-work-queue) u0)))
(define-public (prepare-assemble (background-id uint) (car-id uint) (rim-id uint) (head-id uint)) (add-assemble-work-in-queue background-id car-id rim-id head-id))
(define-public (add-assemble-work-in-queue (background-id uint) (car-id uint) (rim-id uint) (head-id uint)) (ok (begin ;; check user is owner of nft (asserts! (and (is-eq (some tx-sender) (unwrap-panic (contract-call? .backgrounds get-owner background-id))) (and (is-eq (some tx-sender) (unwrap-panic (contract-call? .cars get-owner car-id))) (and (is-eq (some tx-sender) (unwrap-panic (contract-call? .rims get-owner rim-id))) (is-eq (some tx-sender) (unwrap-panic (contract-call? .heads get-owner head-id)))))) err-not-owner) (if (is-eq tx-sender (var-get contract-owner)) true (try! (fee-processing))) (let ((work-queue-value (var-get assemble-work-queue)) (value-to-add { member: tx-sender, background-id: background-id, car-id: car-id, rim-id: rim-id, head-id: head-id })) (var-set assemble-work-queue (begin ;; check user has not already inserted this ;; if the id is already in the queue that means the NFT is burnt => throws err-not-owner when calling for get-owner ;; (asserts! ;; (is-none (index-of work-queue-value value-to-add)) ;; err-invalid ;; ) ;; check user is not abusing the queue (asserts! (< (len (filter is-assemble-value-for-principal work-queue-value)) u5) err-too-many-pending-requests) (unwrap-panic (contract-call? .backgrounds burn-token background-id)) (unwrap-panic (contract-call? .cars burn-token car-id)) (unwrap-panic (contract-call? .rims burn-token rim-id)) (unwrap-panic (contract-call? .heads burn-token head-id)) (append (unwrap-panic (as-max-len? work-queue-value u99)) value-to-add)))))))
(define-private (pop-assemble-work-queue) (ok (let ((work-queue-value (var-get assemble-work-queue))) (var-set assemble-work-queue ;; Remove first element in list (filter is-assemble-first-element work-queue-value)))))
(define-private (is-assemble-first-element (value {background-id: uint, car-id: uint, rim-id: uint, head-id: uint, member: principal})) (let ((first-element (element-at (var-get assemble-work-queue) u0))) (not (and (is-some first-element) (is-eq value (unwrap-panic first-element))))))
(define-private (is-assemble-value-for-principal (value {background-id: uint, car-id: uint, rim-id: uint, head-id: uint, member: principal})) (is-eq (get member value) tx-sender));; eg. case;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.degens mint-uri 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "nice-link");; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.rims mint-name 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "ClassyCream");; ::set_tx_sender STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract add-swap-work-in-queue u1 u1 "rim-type");; ::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract swap-finalize 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "new-nice-link" "ClassyDark" "rim-type");; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.rims get-token-uri u2);; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.degens get-token-uri u4)
(define-data-var swap-work-queue (list 100 {member: principal, degen-id: uint, component-id: uint, component-type: (string-ascii 30)}) (list))
(define-public (swap-finalize (degen-id uint) (member principal) (metadata-uri-dgn (string-ascii 99)) (component-name (string-ascii 30)) (component-type (string-ascii 30))) (begin (asserts! (is-eq tx-sender (var-get contract-owner)) err-invalid) (asserts! (is-eq (some degen-id) (get degen-id (unwrap-panic (get-swap-head-work-queue)))) err-invalid) (unwrap-panic (contract-call? .degens mint-uri member metadata-uri-dgn)) (if (is-eq false (if (is-eq component-type background-type) (unwrap-panic (contract-call? .backgrounds mint-name member component-name)) (if (is-eq component-type car-type) (unwrap-panic (contract-call? .cars mint-name member component-name)) (if (is-eq component-type rim-type) (unwrap-panic (contract-call? .rims mint-name member component-name)) (if (is-eq component-type head-type) (unwrap-panic (contract-call? .heads mint-name member component-name)) false))))) ;; component-type invalid err-component-type-invalid ;; if any mint would have failed the function call would have been rolled back (pop-swap-work-queue))))
(define-read-only (get-swap-work-queue) ;; Get the actual work-queue so that we can process it (ok (var-get swap-work-queue)))
(define-read-only (get-swap-head-work-queue) ;; Get the first element in the work queue so that we can process it (ok (element-at (var-get swap-work-queue) u0)))
(define-public (prepare-swap (degen-id uint) (component-id uint) (component-type (string-ascii 30))) (add-swap-work-in-queue degen-id component-id component-type))
(define-public (add-swap-work-in-queue (degen-id uint) (component-id uint) (component-type (string-ascii 30))) (ok (begin ;; check user is owner of nft (asserts! (and (is-eq (some tx-sender) (unwrap-panic (contract-call? .degens get-owner degen-id))) (is-eq (some tx-sender) (if (is-eq component-type background-type) (unwrap-panic (contract-call? .backgrounds get-owner component-id)) (if (is-eq component-type car-type) (unwrap-panic (contract-call? .cars get-owner component-id)) (if (is-eq component-type rim-type) (unwrap-panic (contract-call? .rims get-owner component-id)) (if (is-eq component-type head-type) (unwrap-panic (contract-call? .heads get-owner component-id)) none)))))) ;; component-type invalid err-not-owner) (if (is-eq tx-sender (var-get contract-owner)) true (try! (fee-processing))) (let ((work-queue-value (var-get swap-work-queue)) (value-to-add { member: tx-sender, degen-id: degen-id, component-id: component-id, component-type: component-type })) (var-set swap-work-queue (begin ;; check user has not already inserted this ;; if the id is already in the queue that means the NFT is burnt => throws err-not-owner when calling for get-owner ;; (asserts! ;; (is-none (index-of work-queue-value value-to-add)) ;; err-invalid ;; ) ;; check user is not abusing the queue (asserts! (< (len (filter is-swap-value-for-principal work-queue-value)) u5) err-too-many-pending-requests) (unwrap-panic (contract-call? .degens burn-token degen-id)) (if (is-eq component-type background-type) (unwrap-panic (contract-call? .backgrounds burn-token component-id)) (if (is-eq component-type car-type) (unwrap-panic (contract-call? .cars burn-token component-id)) (if (is-eq component-type rim-type) (unwrap-panic (contract-call? .rims burn-token component-id)) (if (is-eq component-type head-type) (unwrap-panic (contract-call? .heads burn-token component-id)) false))));; component-type invalid (append (unwrap-panic (as-max-len? work-queue-value u99)) value-to-add)))))))
(define-private (pop-swap-work-queue) (ok (let ((work-queue-value (var-get swap-work-queue))) (var-set swap-work-queue ;; Remove first element in list (filter is-swap-first-element work-queue-value)))))
(define-private (is-swap-first-element (value {degen-id: uint, component-id: uint, component-type: (string-ascii 30), member: principal})) (let ((first-element (element-at (var-get swap-work-queue) u0))) (not (and (is-some first-element) (is-eq value (unwrap-panic first-element))))))
(define-private (is-swap-value-for-principal (value {degen-id: uint, component-id: uint, component-type: (string-ascii 30), member: principal})) (is-eq (get member value) tx-sender));; eg. case;; ::set_tx_sender STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.miami-degens claim);; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.nyc-degens claim);; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract add-merge-work-in-queue u1 "miami");; ::set_tx_sender ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM;; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract get-merge-work-queue);; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.upgrade-contract merge-finalize 'STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 "nice-new-nft");; (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.degens get-token-uri u1)
(define-data-var merge-work-queue (list 100 {member: principal, degen-id: uint, degen-type: (string-ascii 30)}) (list))
(define-public (merge-finalize (degen-id uint) (member principal) (metadata-uri-dgn (string-ascii 99))) (begin (asserts! (is-eq tx-sender (var-get contract-owner)) err-invalid) (asserts! (is-eq (some degen-id) (get degen-id (unwrap-panic (get-merge-head-work-queue)))) err-invalid) (unwrap-panic (contract-call? .degens mint-uri member metadata-uri-dgn)) (pop-merge-work-queue)))
(define-read-only (get-merge-work-queue) ;; Get the actual work-queue so that we can process it (ok (var-get merge-work-queue)))
(define-read-only (get-merge-head-work-queue) ;; Get the first element in the work queue so that we can process it (ok (element-at (var-get merge-work-queue) u0)))
(define-public (prepare-upgrade (degen-id uint) (degen-type (string-ascii 30))) (add-merge-work-in-queue degen-id degen-type))
(define-public (add-merge-work-in-queue (degen-id uint) (degen-type (string-ascii 30))) (ok (begin ;; check user is owner of old Degen nft (asserts! (is-eq (some tx-sender) (if (is-eq degen-type miami-type) (unwrap-panic (contract-call? .miami-degens get-owner degen-id)) (if (is-eq degen-type nyc-type) (unwrap-panic (contract-call? .nyc-degens get-owner degen-id)) none))) err-not-owner) (if (is-eq tx-sender (var-get contract-owner)) true (try! (fee-processing))) (let ((work-queue-value (var-get merge-work-queue)) (value-to-add { member: tx-sender, degen-id: degen-id, degen-type: degen-type })) (var-set merge-work-queue (begin ;; already insured by the fact that the nft is burned ;; ;; check user has not already inserted this ;; (asserts! ;; (is-none (index-of work-queue-value value-to-add)) ;; err-invalid ;; ) ;; check user is not abusing the queue (asserts! (< (len (filter is-merge-value-for-principal work-queue-value)) u5) err-too-many-pending-requests) ;; (unwrap-panic (contract-call? .old-degens burn-token degen-id)) (some (burn-old-nft degen-id degen-type)) (append (unwrap-panic (as-max-len? work-queue-value u99)) value-to-add)))))))
(define-private (pop-merge-work-queue) (ok (let ((work-queue-value (var-get merge-work-queue))) (var-set merge-work-queue ;; Remove first element in list (filter is-merge-first-element work-queue-value)))))
(define-private (burn-old-nft (degen-id uint) (degen-type (string-ascii 30))) (if (is-eq false (if (is-eq degen-type miami-type) (unwrap-panic (contract-call? .miami-degens transfer degen-id tx-sender burn-address)) (if (is-eq degen-type nyc-type) (unwrap-panic (contract-call? .nyc-degens transfer degen-id tx-sender burn-address)) false))) err-component-type-invalid (ok (some degen-id))))
(define-private (is-merge-first-element (value {degen-id: uint, degen-type: (string-ascii 30), member: principal})) (let ((first-element (element-at (var-get merge-work-queue) u0))) (not (and (is-some first-element) (is-eq value (unwrap-panic first-element))))))
(define-private (is-merge-value-for-principal (value {degen-id: uint, degen-type: (string-ascii 30), member: principal})) (is-eq (get member value) tx-sender))Transfer fee function
;; fees: 0.69 stx(define-private (fee-processing) (stx-transfer? u690000 tx-sender (var-get contract-owner)))