Source Code

(define-constant CONTRACT-OWNER tx-sender)
(define-constant MAX-SUPPLY u5000)

(define-data-var artist-address principal 'SP3CFHSKDCW3761DD1P6X3VEC3NHKTJ4H0XJT79D6)
(define-data-var member1-address principal 'SPN7M36SSAZQZZ1T4JRQF6PRJDXPT4VRW7Y8QRR)
(define-data-var member2-address principal 'SP2JVKEW0YKTNT3SCTQSPF2V3DDVFFNG6B2TF9ZSV)
(define-data-var project-address principal 'SPSSETN3G8A1V7PB0M6A8Q27WFG5J9EMWTDE1WZA)
(define-data-var price uint u25000000)
(define-data-var nft-contract principal .screenfiends-nft)
(define-data-var premint-live bool false)
(define-data-var mint-live bool false)
(define-map mint-passes principal uint)
(define-map mint-count principal uint)

(define-data-var current-phase uint u1)
(define-map phase-active uint bool)
(define-map phase-supply uint {start: uint, end: uint})
(define-map whitelist-next-phase principal uint)
(define-map phase-presale-active uint bool)
(define-map phase-publicsale-active uint bool)


(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-MINT-NOT-LIVE (err u402))
(define-constant ERR-SOLD-OUT (err u403))
(define-constant ERR-NOT-ENOUGH-MINT-PASSES (err u405))
(define-constant ERR-SUPPLY-NOT-DEFINED (err u404))


(define-private (is-owner)
    (is-eq tx-sender CONTRACT-OWNER))

(define-public (set-price (new-price uint))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set price new-price)
        (ok true)))

(define-read-only (get-price)
    (ok (var-get price)))

(define-public (set-nft-contract (contract principal))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set nft-contract contract)
        (ok true)))

(define-public (set-artist-address (address principal ))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set artist-address address)
        (ok true)))

(define-public (set-member1-address (address principal ))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set member1-address address)
        (ok true)))

(define-public (set-member2-address (address principal ))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set member2-address address)
        (ok true)))


(define-public (set-project-address (address principal ))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set project-address address)
        (ok true)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: initialize-phase-supply
;; Description:
;;   Dynamically calculates and populates the `phase-supply` map with values
;;   for 5 phases, where the total supply is evenly divided among the phases.
;;
;; Parameters:
;;   - max-supply (uint): The total supply of NFTs to be divided into phases.
;;
;; Returns:
;;   - (ok true) if the initialization is successful.
;;   - (err u401) if called by a non-owner.
;;
;; Notes:
;;   - Divides the max-supply into 5 equal chunks.
;;   - Handles cases where max-supply is not divisible by 5.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (initialize-phase-supply (max-supply uint))
  (begin
    (asserts! (is-owner) ERR-NOT-AUTHORIZED)

    ;; Calculate the phase size
    (let 
      (
        (phase-size (/ max-supply u5)) ;; Divide the supply into 5 phases
      )

      ;; Initialize each phase
      (map-set phase-supply u1 {start: u1, end: phase-size})
      (map-set phase-supply u2 {start: (+ phase-size u1), end: (* phase-size u2)})
      (map-set phase-supply u3 {start: (+ (* phase-size u2) u1), end: (* phase-size u3)})
      (map-set phase-supply u4 {start: (+ (* phase-size u3) u1), end: (* phase-size u4)})
      (map-set phase-supply u5 {start: (+ (* phase-size u4) u1), end: max-supply})

      (ok true)
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: set-current-phase
;; Description:
;;   Sets the current active phase for the contract. Only callable by the contract owner.
;;
;; Parameters:
;;   - phase (uint): The phase number to set as the current phase.
;;
;; Returns:
;;   - (ok true) if the operation is successful.
;;   - (err u401) if the caller is not authorized.
;;
;; Notes:
;;   - This function updates the contract's `current-phase` variable.
;;   - Ensures that only the contract owner can make this change.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (set-current-phase (phase uint))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (var-set current-phase phase)
        (ok true)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: get-current-phase
;; Description:
;;   Retrieves the current active phase of the contract.
;;
;; Parameters:
;;   - None
;;
;; Returns:
;;   - (ok uint): The current phase number.
;;
;; Notes:
;;   - This function provides a read-only view of the `current-phase` variable.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (get-current-phase)
    (ok (var-get current-phase)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: get-phase-supply
;; Description:
;;   Retrieves the supply range for a given phase, including the start and end
;;   token IDs for the phase.
;;
;; Parameters:
;;   - phase (uint): The phase number whose supply range is to be retrieved.
;;
;; Returns:
;;   - (ok {start: uint, end: uint}) if the phase exists.
;;   - (ok none) if the phase is not set.
;;
;; Notes:
;;   - The supply range is defined as a map with `start` and `end` values.
;;   - This function provides a read-only view of the phase supply.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (get-phase-supply (phase uint))
    (ok (map-get? phase-supply phase)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: get-phase-remaining-supply
;; Description:
;;   Retrieves the remaining supply for a given phase, calculated based
;;   on the last minted token ID and the phase's `start` and `end` values.
;;
;; Parameters:
;;   - phase-id (uint): The phase number whose remaining supply is to be retrieved.
;;
;; Returns:
;;   - (ok uint): The remaining supply for the given phase.
;;
;; Notes:
;;   - Calls the `.screenfiends-nft` contract to get the last minted token ID.
;;   - Retrieves the `start` and `end` values from the `phase-supply` map.
;;   - If `last-id` is outside the phase's range, adjusts the remaining supply accordingly.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (get-phase-remaining-supply (phase-id uint))
  (let
    (
      (last-id (unwrap-panic (contract-call? .screenfiends-nft get-last-token-id)))
      (phase-supply-config (unwrap! (map-get? phase-supply phase-id) (err ERR-SUPPLY-NOT-DEFINED)))
      (start-supply (get start phase-supply-config))
      (end-supply (get end phase-supply-config))
    )
    (if (>= last-id end-supply)
        ;; If `last-id` is beyond or equal to the phase's range, no supply left
        (ok u0)
        ;; Otherwise, calculate remaining supply within the phase range
        (if (< last-id start-supply)
            ;; If `last-id` is below the phase's range, full supply remains
            (ok (- (+ end-supply u1) start-supply))
            ;; Else, remaining supply is adjusted for minted tokens
            (ok (- end-supply last-id))
        )
    )
  )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: set-phase-active
;; Description:
;;   Sets a phase actve
;;
;; Parameters:
;;   - phase (uint) - The phase number to set active
;;   - active (bool) - The status to set the phase
;;
;; Returns:
;;   - (ok bool): true indicating successful update
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (set-phase-active (phase uint) (active bool))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (map-set phase-active phase active)
        (ok true)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: is-phase-active
;; Description:
;;   Checks whether a specific phase is active.
;;
;; Parameters:
;;   - phase (uint): The phase number to check.
;;
;; Returns:
;;   - (ok bool): `true` if the phase is active, `false` otherwise.
;;
;; Notes:
;;   - Uses the `phase-active` map to determine the active status of the phase.
;;   - If no value is set for the phase in the `phase-active` map, defaults to `false`.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (is-phase-active (phase uint))
    (ok (default-to false (map-get? phase-active phase))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: set-phase-presale-active
;; Description:
;;   Enables or disables the presale status for a specific phase.
;;
;; Parameters:
;;   - phase (uint): The phase number to update.
;;   - active (bool): `true` to enable presale, `false` to disable it.
;;
;; Returns:
;;   - (ok true) if the operation is successful.
;;   - (err u401) if the caller is not authorized.
;;
;; Notes:
;;   - Only callable by the contract owner.
;;   - Updates the `phase-presale-active` map with the provided status.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (set-phase-presale-active (phase uint) (active bool))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (map-set phase-presale-active phase active)
        (ok true)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: set-phase-publicsale-active
;; Description:
;;   Enables or disables the public sale status for a specific phase.
;;
;; Parameters:
;;   - phase (uint): The phase number to update.
;;   - active (bool): `true` to enable public sale, `false` to disable it.
;;
;; Returns:
;;   - (ok true) if the operation is successful.
;;   - (err u401) if the caller is not authorized.
;;
;; Notes:
;;   - Only callable by the contract owner.
;;   - Updates the `phase-publicsale-active` map with the provided status.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (set-phase-publicsale-active (phase uint) (active bool))
    (begin
        (asserts! (is-owner) ERR-NOT-AUTHORIZED)
        (map-set phase-publicsale-active phase active)
        (ok true)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: is-phase-presale-active
;; Description:
;;   Checks whether the presale is active for a specific phase.
;;
;; Parameters:
;;   - phase (uint): The phase number to check.
;;
;; Returns:
;;   - (ok bool): `true` if the presale is active, `false` otherwise.
;;
;; Notes:
;;   - Uses the `phase-presale-active` map to determine the status.
;;   - Defaults to `false` if the phase is not set in the map.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (is-phase-presale-active (phase uint))
    (ok (default-to false (map-get? phase-presale-active phase))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: is-phase-publicsale-active
;; Description:
;;   Checks whether the public sale is active for a specific phase.
;;
;; Parameters:
;;   - phase (uint): The phase number to check.
;;
;; Returns:
;;   - (ok bool): `true` if the public sale is active, `false` otherwise.
;;
;; Notes:
;;   - Uses the `phase-publicsale-active` map to determine the status.
;;   - Defaults to `false` if the phase is not set in the map.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (is-phase-publicsale-active (phase uint))
    (ok (default-to false (map-get? phase-publicsale-active phase))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: add-mintpasses
;; Description:
;;   Adds or updates the mint passes for a list of addresses. Each address
;;   can be assigned a specific number of mint passes.
;;
;; Parameters:
;;   - entries (list 2000 {address: principal, quantity: uint}):
;;       A list of objects where:
;;       - `address` (principal): The principal address to assign mint passes to.
;;       - `quantity` (uint): The number of mint passes to assign.
;;
;; Returns:
;;   - (ok true) if the operation is successful.
;;   - (err u401) if the caller is not authorized.
;;
;; Notes:
;;   - Only callable by the contract owner.
;;   - Iterates over the `entries` list and uses the `add-mintpasses-iter` function
;;     to update the `mint-passes` map.
;;   - Prints the total number of addresses processed for debugging purposes.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (add-mintpasses (entries (list 2000 {address: principal, quantity: uint})))
  (begin
    (asserts! (is-owner) ERR-NOT-AUTHORIZED)
    (let
      ((index-reached (fold add-mintpasses-iter entries u0)))
      (print {total-mintpasses-added: index-reached})
      (ok true))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function Name: get-mint-passes-remaining
;; Description:
;;   Calculates the remaining number of mint passes available for a given address.
;;
;; Parameters:
;;   - address (principal): The address to check for remaining mint passes.
;;
;; Returns:
;;   - (ok uint): The number of remaining mint passes for the given address.
;;
;; Notes:
;;   - Retrieves the total mint passes (`allowed`) from the `mint-passes` map.
;;   - Retrieves the number of NFTs minted (`minted`) from the `mint-count` map.
;;   - Calculates the remaining passes as `allowed - minted`. Defaults both
;;     values to `u0` if no entry exists in their respective maps.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-read-only (get-mint-passes-remaining (address principal))
    (let (
        (minted (default-to u0 (map-get? mint-count address)))
        (allowed (default-to u0 (map-get? mint-passes address)))
    )
        (ok (- allowed minted))))


(define-read-only (get-mint-passes (address principal))
  (ok (default-to u0 (map-get? mint-passes address))))


(define-public (clear-mintpasses (addresses (list 2000 principal)))
  (begin
    (asserts! (is-owner) ERR-NOT-AUTHORIZED)
    (let
      ((index-reached (fold clear-mintpasses-iter addresses u0)))
      (print {total-mintpasses-cleared: index-reached})
      (ok true))))


(define-private (clear-mintpasses-iter (address principal) (next-index uint))
  (begin
    (map-delete mint-passes address)
    (+ next-index u1)))

(define-private (add-mintpasses-iter (entry {address: principal, quantity: uint}) (next-index uint))
  (begin
    (map-set mint-passes (get address entry) (get quantity entry))
    (+ next-index u1)))

(define-read-only (get-mint-count (address principal))
  (ok (default-to u0 (map-get? mint-count address))))


(define-private (direct-mint (new-owner principal))
    (contract-call? .screenfiends-nft mint new-owner))


(define-private (mnt)
  (let
    (
      (active-phase (var-get current-phase))
      (phase-is-active (unwrap-panic (is-phase-active active-phase)))
      (phase-premint-live (default-to false (map-get? phase-presale-active active-phase)))
      (phase-public-mint-live (default-to false (map-get? phase-publicsale-active active-phase)))
      (phase-supply-config (unwrap-panic (get-phase-supply active-phase)))
      (remaining-supply (unwrap-panic (get-phase-remaining-supply active-phase)))
      (mintpass-passes (unwrap-panic (get-mint-passes-remaining tx-sender)))
      (max-phase-supply (get end phase-supply-config))
    )

    ;; Check if there are NFTs left to mint
    (asserts! (> remaining-supply u0) ERR-SOLD-OUT)

    (asserts! phase-is-active ERR-MINT-NOT-LIVE)

    ;; Check if mint-live or premint-live is true, otherwise throw error
    (if (or phase-public-mint-live phase-premint-live)
        ;; If mint-live is true, allow public mint
        (if phase-public-mint-live
            (direct-mint tx-sender)

            ;; Otherwise, check if premint mint is live and mintpass passes are available
            (if (> mintpass-passes u0)
                (begin
                  ;; Update mint count and mint for mintpass pass holders
                  (map-set mint-count tx-sender (+ (default-to u0 (map-get? mint-count tx-sender)) u1))
                  (direct-mint tx-sender)
                )
                ERR-NOT-ENOUGH-MINT-PASSES))
        ERR-MINT-NOT-LIVE)))

(define-private (mint-iter (ignore uint) (prior {minted: uint, error: (optional (response bool uint)), continue: bool, count: uint}))
    (if (and (< (get minted prior) (get count prior)) (get continue prior))
        (match (mnt)
            success (merge prior {minted: (+ u1 (get minted prior))})
            error (merge prior {error: (some (err error)), continue: false}))
        prior))

(define-public (mint (count uint))
    (let
        (
            (total-price (* (var-get price) count))
            (art-addr (var-get artist-address))
            (member1-addr (var-get member1-address))
            (member2-addr (var-get member2-address))
            (project-addr (var-get project-address))
            (total-artist-comm (/ (* total-price u4750) u10000))
            (total-member1-comm (/ (* total-price u2375) u10000))
            (total-member2-comm (/ (* total-price u2375) u10000))
            (total-project-comm (/ (* total-price u500) u10000))
            (loop-result
                (begin
                    (try! (stx-transfer? total-artist-comm tx-sender art-addr))
                    (try! (stx-transfer? total-member1-comm tx-sender member1-addr))
                    (try! (stx-transfer? total-member2-comm tx-sender member2-addr))
                    (try! (stx-transfer? total-project-comm tx-sender project-addr))
                    (fold mint-iter
                        (list u1 u2 u3 u4 u5 u6 u7 u8 u9 u10 u11 u12 u13 u14 u15 u16 u17 u18 u19 u20 u21 u22 u23 u24 u25)
                        {minted: u0, error: none, continue: true, count: count}
                    )
                )
            )
        )
        (if (is-some (get error loop-result))
            (unwrap-panic (get error loop-result))
            (ok true))))




Functions (30)

FunctionAccessArgs
is-ownerprivate
set-pricepublicnew-price: uint
get-priceread-only
set-nft-contractpubliccontract: principal
set-artist-addresspublicaddress: principal
set-member1-addresspublicaddress: principal
set-member2-addresspublicaddress: principal
set-project-addresspublicaddress: principal
initialize-phase-supplypublicmax-supply: uint
set-current-phasepublicphase: uint
get-current-phaseread-only
get-phase-supplyread-onlyphase: uint
get-phase-remaining-supplyread-onlyphase-id: uint
set-phase-activepublicphase: uint, active: bool
is-phase-activeread-onlyphase: uint
set-phase-presale-activepublicphase: uint, active: bool
set-phase-publicsale-activepublicphase: uint, active: bool
is-phase-presale-activeread-onlyphase: uint
is-phase-publicsale-activeread-onlyphase: uint
add-mintpassespublicentries: (list 2000 {address: principal, quantity: uint}
get-mint-passes-remainingread-onlyaddress: principal
get-mint-passesread-onlyaddress: principal
clear-mintpassespublicaddresses: (list 2000 principal
clear-mintpasses-iterprivateaddress: principal, next-index: uint
add-mintpasses-iterprivateentry: {address: principal, quantity: uint}, next-index: uint
get-mint-countread-onlyaddress: principal
direct-mintprivatenew-owner: principal
mntprivate
mint-iterprivateignore: uint, prior: {minted: uint, error: (optional (response bool uint
mintpubliccount: uint