;; title: wrapped-stx
;; version:
;; summary:
;; description:
;; Music Royalty Distribution Smart Contract
(define-constant ERR-UNAUTHORIZED-ACCESS (err u100))
(define-constant ERR-INVALID-ROYALTY-PERCENTAGE (err u101))
(define-constant ERR-DUPLICATE-SONG-ENTRY (err u102))
(define-constant ERR-SONG-NOT-FOUND (err u103))
(define-constant ERR-INSUFFICIENT-PAYMENT (err u104))
(define-constant ERR-INVALID-RECIPIENT (err u105))
(define-constant ERR-PAYMENT-DISTRIBUTION-FAILED (err u106))
(define-constant ERR-INVALID-STRING-LENGTH (err u107))
(define-constant ERR-INVALID-SONG-TITLE (err u108))
(define-constant ERR-INVALID-PARTICIPANT-ROLE (err u109))
(define-constant ERR-INVALID-ARTIST (err u110))
(define-constant ERR-INVALID-ADMIN (err u111))
;; Data Structures for Music Rights Management
(define-map music-catalog
{ song-id: uint }
{
title: (string-ascii 50),
primary-artist: principal,
total-revenue: uint,
release-date: uint,
is-active: bool,
}
)
(define-map royalty-allocations
{
song-id: uint,
rights-holder: principal,
}
{
percentage: uint,
role: (string-ascii 20),
earned-royalties: uint,
}
)
;; Contract State Variables
(define-data-var total-registered-tracks uint u0)
(define-data-var contract-owner principal tx-sender)
;; Validation Helpers
(define-private (is-valid-royalty-share (share {
percentage: uint,
role: (string-ascii 20),
earned-royalties: uint,
}))
(> (get percentage share) u0)
)
(define-private (is-contract-owner)
(is-eq tx-sender (var-get contract-owner))
)
(define-private (validate-royalty-percentage (percentage uint))
(and (>= percentage u0) (<= percentage u100))
)
(define-private (validate-ascii-string (input (string-ascii 50)))
(let ((length (len input)))
(and (> length u0) (<= length u50))
)
)
(define-private (validate-participant-role (role (string-ascii 20)))
(let ((length (len role)))
(and (> length u0) (<= length u20))
)
)
(define-private (validate-rights-holder (holder principal))
(and
(not (is-eq holder tx-sender))
(not (is-eq holder (var-get contract-owner)))
)
)
;; Read-Only Query Functions
(define-read-only (get-track-details (song-id uint))
(map-get? music-catalog { song-id: song-id })
)
(define-read-only (get-royalty-details
(song-id uint)
(rights-holder principal)
)
(map-get? royalty-allocations {
song-id: song-id,
rights-holder: rights-holder,
})
)
(define-read-only (get-total-tracks)
(var-get total-registered-tracks)
)
(define-read-only (get-track-royalty-shares (song-id uint))
(let (
(track-info (get-track-details song-id))
(primary-artist (match track-info
record (get primary-artist record)
tx-sender
))
)
(let ((distribution (get-royalty-details song-id primary-artist)))
(match distribution
share (list {
rights-holder: primary-artist,
percentage: (get percentage share),
})
(list)
)
)
)
)
;; Royalty Distribution Mechanism
(define-private (calculate-rights-holder-payment
(rights-share {
rights-holder: principal,
percentage: uint,
})
(total-payment uint)
)
(let ((holder-payment (/ (* total-payment (get percentage rights-share)) u100)))
(if (> holder-payment u0)
(match (stx-transfer? holder-payment tx-sender (get rights-holder rights-share))
success total-payment
error u0
)
u0
)
)
)
(define-private (distribute-royalties
(song-id uint)
(total-payment uint)
)
(let (
(royalty-distribution-list (get-track-royalty-shares song-id))
(total-distributed (fold calculate-rights-holder-payment royalty-distribution-list
total-payment
))
)
(begin
(asserts! (> (len royalty-distribution-list) u0) ERR-SONG-NOT-FOUND)
(asserts! (> total-distributed u0) ERR-PAYMENT-DISTRIBUTION-FAILED)
(ok total-distributed)
)
)
)
;; Administrative Functions
(define-public (register-track
(track-title (string-ascii 50))
(primary-artist principal)
)
(let ((new-track-id (+ (var-get total-registered-tracks) u1)))
(begin
(asserts! (is-contract-owner) ERR-UNAUTHORIZED-ACCESS)
(asserts! (validate-ascii-string track-title) ERR-INVALID-SONG-TITLE)
(asserts! (validate-rights-holder primary-artist) ERR-INVALID-ARTIST)
(map-set music-catalog { song-id: new-track-id } {
title: track-title,
primary-artist: primary-artist,
total-revenue: u0,
release-date: stacks-block-height,
is-active: true,
})
(var-set total-registered-tracks new-track-id)
(ok new-track-id)
)
)
)
(define-public (set-royalty-allocation
(song-id uint)
(rights-holder principal)
(percentage uint)
(participant-role (string-ascii 20))
)
(let ((track-record (get-track-details song-id)))
(begin
(asserts! (is-some track-record) ERR-SONG-NOT-FOUND)
(asserts! (validate-royalty-percentage percentage)
ERR-INVALID-ROYALTY-PERCENTAGE
)
(asserts! (validate-participant-role participant-role)
ERR-INVALID-PARTICIPANT-ROLE
)
(asserts! (validate-rights-holder rights-holder) ERR-INVALID-RECIPIENT)
(map-set royalty-allocations {
song-id: song-id,
rights-holder: rights-holder,
} {
percentage: percentage,
role: participant-role,
earned-royalties: u0,
})
(ok true)
)
)
)
(define-public (process-royalty-payment
(song-id uint)
(payment-amount uint)
)
(let ((track-record (get-track-details song-id)))
(begin
(asserts! (is-some track-record) ERR-SONG-NOT-FOUND)
(asserts! (>= (stx-get-balance tx-sender) payment-amount)
ERR-INSUFFICIENT-PAYMENT
)
(try! (distribute-royalties song-id payment-amount))
(map-set music-catalog { song-id: song-id }
(merge (unwrap-panic track-record) { total-revenue: (+ (get total-revenue (unwrap-panic track-record)) payment-amount) })
)
(ok true)
)
)
)
(define-public (update-track-status
(song-id uint)
(is-active bool)
)
(let ((track-record (get-track-details song-id)))
(begin
(asserts! (is-contract-owner) ERR-UNAUTHORIZED-ACCESS)
(asserts! (is-some track-record) ERR-SONG-NOT-FOUND)
(map-set music-catalog { song-id: song-id }
(merge (unwrap-panic track-record) { is-active: is-active })
)
(ok true)
)
)
)
(define-public (transfer-ownership (new-owner principal))
(begin
(asserts! (is-contract-owner) ERR-UNAUTHORIZED-ACCESS)
(asserts! (validate-rights-holder new-owner) ERR-INVALID-ADMIN)
(var-set contract-owner new-owner)
(ok true)
)
)
;; Contract Initialization
(begin
(var-set total-registered-tracks u0)
)