;; 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))) ;; Prevent self-transfers
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))) ;; Prevent self-transfers
err-not-authorized)
(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)) ;; Ensure asset is transferable
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))