Source Code

;; Gamin Gaming Platform Smart Contract
;; Handles in-game asset ownership and trading functionality

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-not-authorized (err u102))
(define-constant err-invalid-input (err u103))
(define-constant err-invalid-price (err u104))
(define-constant max-level u100)
(define-constant max-experience u10000)
(define-constant max-metadata-length u256)
(define-constant max-batch-size u10) ;; Limit batch operations to prevent potential gas issues

;; Data Variables
(define-map assets
  { asset-id: uint }
  {
    owner: principal,
    metadata-uri: (string-utf8 256),
    transferable: bool,
  }
)

(define-map asset-prices
  { asset-id: uint }
  { price: uint }
)

(define-map player-stats
  { player: principal }
  {
    experience: uint,
    level: uint,
  }
)

(define-map marketplace-listings
  { asset-id: uint }
  {
    seller: principal,
    price: uint,
    listed-at: uint,
  }
)

;; Asset Counter
(define-data-var asset-counter uint u0)

;; Helper Functions

;; Validate asset exists and return asset data
(define-private (get-asset-checked (asset-id uint))
  (let ((asset (map-get? assets { asset-id: asset-id })))
    (asserts!
      (and
        (is-some asset)
        (<= asset-id (var-get asset-counter))
      )
      err-not-found
    )
    (ok (unwrap-panic asset))
  )
)

;; Validate metadata URI length
(define-private (validate-metadata-uri (uri (string-utf8 256)))
  (let ((uri-length (len uri)))
    (and
      (> uri-length u0)
      (<= uri-length max-metadata-length)
    )
  )
)

;; Public Functions

;; Batch Mint new gaming assets
(define-public (batch-mint-assets
    (metadata-uris (list 10 (string-utf8 256)))
    (transferable-list (list 10 bool))
  )
  (begin
    (asserts! (is-eq tx-sender contract-owner) err-owner-only)
    (asserts!
      (and
        (> (len metadata-uris) u0)
        (<= (len metadata-uris) max-batch-size)
        (is-eq (len metadata-uris) (len transferable-list))
      )
      err-invalid-input
    )
    (let ((minted-assets (map mint-single-asset metadata-uris transferable-list)))
      (ok minted-assets)
    )
  )
)

;; Helper function for batch minting
(define-private (mint-single-asset
    (uri (string-utf8 256))
    (transferable bool)
  )
  (let ((asset-id (+ (var-get asset-counter) u1)))
    (asserts! (validate-metadata-uri uri) err-invalid-input)
    (map-set assets { asset-id: asset-id } {
      owner: contract-owner,
      metadata-uri: uri,
      transferable: transferable,
    })
    (var-set asset-counter asset-id)
    (ok asset-id)
  )
)

;; Batch Transfer assets
(define-public (batch-transfer-assets
    (asset-ids (list 10 uint))
    (recipients (list 10 principal))
  )
  (begin
    (asserts!
      (and
        (> (len asset-ids) u0)
        (<= (len asset-ids) max-batch-size)
        (is-eq (len asset-ids) (len recipients))
      )
      err-invalid-input
    )
    (let ((transfers (map transfer-single-asset asset-ids recipients)))
      (ok transfers)
    )
  )
)

;; Helper function for batch transfer
(define-private (transfer-single-asset
    (asset-id uint)
    (recipient principal)
  )
  (let ((asset (unwrap-panic (get-asset-checked asset-id))))
    (asserts!
      (and
        (is-eq (get owner asset) tx-sender)
        (get transferable asset)
        (not (is-eq recipient tx-sender))
      )
      err-not-authorized
    )
    (map-set assets { asset-id: asset-id } {
      owner: recipient,
      metadata-uri: (get metadata-uri asset),
      transferable: (get transferable asset),
    })
    (ok true)
  )
)
;; Changed to return (ok true)

;; Mint single asset
(define-public (mint-asset
    (metadata-uri (string-utf8 256))
    (transferable bool)
  )
  (let ((asset-id (+ (var-get asset-counter) u1)))
    (asserts! (is-eq tx-sender contract-owner) err-owner-only)
    (asserts! (validate-metadata-uri metadata-uri) err-invalid-input)
    (map-set assets { asset-id: asset-id } {
      owner: tx-sender,
      metadata-uri: metadata-uri,
      transferable: transferable,
    })
    (var-set asset-counter asset-id)
    (ok asset-id)
  )
)

;; Transfer asset ownership
(define-public (transfer-asset
    (asset-id uint)
    (recipient principal)
  )
  (begin
    (asserts! (<= asset-id (var-get asset-counter)) err-invalid-input)
    (let ((asset (try! (get-asset-checked asset-id))))
      (asserts!
        (and
          (is-eq (get owner asset) tx-sender)
          (get transferable asset)
          (not (is-eq recipient tx-sender))
        )
        err-not-authorized ;; Prevent self-transfers
      )
      (map-set assets { asset-id: asset-id } {
        owner: recipient,
        metadata-uri: (get metadata-uri asset),
        transferable: (get transferable asset),
      })
      (ok true)
    )
  )
)

;; List asset for sale with enhanced marketplace listing
(define-public (list-asset-for-sale
    (asset-id uint)
    (price uint)
  )
  (begin
    (asserts! (<= asset-id (var-get asset-counter)) err-invalid-input)
    (let ((asset (try! (get-asset-checked asset-id))))
      (asserts!
        (and
          (is-eq (get owner asset) tx-sender)
          (> price u0)
          (get transferable asset)
        )
        err-invalid-price
      )
      (map-set marketplace-listings { asset-id: asset-id } {
        seller: tx-sender,
        price: price,
        listed-at: stacks-block-height,
      })
      (ok true)
    )
  )
)

;; Purchase listed asset with enhanced marketplace mechanics
(define-public (purchase-asset (asset-id uint))
  (begin
    (asserts! (<= asset-id (var-get asset-counter)) err-invalid-input)
    (let (
        (asset (try! (get-asset-checked asset-id)))
        (listing (unwrap! (map-get? marketplace-listings { asset-id: asset-id })
          err-not-found
        ))
      )
      (asserts!
        (and
          (not (is-eq (get seller listing) tx-sender))
          (get transferable asset)
        )
        err-not-authorized
      )
      (try! (stx-transfer? (get price listing) tx-sender (get seller listing)))
      (map-set assets { asset-id: asset-id } {
        owner: tx-sender,
        metadata-uri: (get metadata-uri asset),
        transferable: (get transferable asset),
      })
      (map-delete marketplace-listings { asset-id: asset-id })
      (ok true)
    )
  )
)

;; Remove asset from marketplace listing
(define-public (delist-asset (asset-id uint))
  (begin
    ;; Validate asset-id is within the range of minted assets
    (asserts! (<= asset-id (var-get asset-counter)) err-invalid-input)

    ;; Try to get the listing, return error if not found
    (let ((listing (unwrap! (map-get? marketplace-listings { asset-id: asset-id })
        err-not-found
      )))
      ;; Ensure only the seller can delist
      (asserts! (is-eq tx-sender (get seller listing)) err-not-authorized)

      ;; Delete the marketplace listing
      (map-delete marketplace-listings { asset-id: asset-id })

      ;; Return success
      (ok true)
    )
  )
)

;; Update player stats with validation
(define-public (update-player-stats
    (experience uint)
    (level uint)
  )
  (begin
    (asserts! (<= experience max-experience) err-invalid-input)
    (asserts! (<= level max-level) err-invalid-input)
    (map-set player-stats { player: tx-sender } {
      experience: experience,
      level: level,
    })
    (ok true)
  )
)

;; Read-only Functions

;; Get asset details
(define-read-only (get-asset-details (asset-id uint))
  (if (<= asset-id (var-get asset-counter))
    (map-get? assets { asset-id: asset-id })
    none
  )
)

;; Get marketplace listing details
(define-read-only (get-marketplace-listing (asset-id uint))
  (map-get? marketplace-listings { asset-id: asset-id })
)

;; Get player stats
(define-read-only (get-player-stats (player principal))
  (map-get? player-stats { player: player })
)

;; Get total assets minted
(define-read-only (get-total-assets)
  (var-get asset-counter)
)

Functions (12)

FunctionAccessArgs
purchase-assetpublicasset-id: uint
get-asset-checkedprivateasset-id: uint
validate-metadata-uriprivateuri: (string-utf8 256
batch-mint-assetspublicmetadata-uris: (list 10 (string-utf8 256
mint-single-assetprivateuri: (string-utf8 256
batch-transfer-assetspublicasset-ids: (list 10 uint
mint-assetpublicmetadata-uri: (string-utf8 256
delist-assetpublicasset-id: uint
get-asset-detailsread-onlyasset-id: uint
get-marketplace-listingread-onlyasset-id: uint
get-player-statsread-onlyplayer: principal
get-total-assetsread-only