Source Code

;; Music Royalty Distribution Smart Contract
;; This contract manages music royalty distributions among artists, producers, and rights holders

;; Error codes
(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-DOES-NOT-EXIST (err u103))
(define-constant ERR-INSUFFICIENT-PAYMENT-FUNDS (err u104))
(define-constant ERR-INVALID-ROYALTY-RECIPIENT (err u105))
(define-constant ERR-PAYMENT-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-PRIMARY-ARTIST (err u110))
(define-constant ERR-INVALID-ADMINISTRATOR (err u111))

;; Data structures
(define-map RegisteredSongs
    { song-identifier: uint }
    {
        song-title: (string-ascii 50),
        primary-artist: principal,
        accumulated-revenue: uint,
        publication-date: uint,
        song-status-active: bool
    }
)

(define-map RoyaltyDistribution
    { song-identifier: uint, royalty-recipient: principal }
    {
        royalty-percentage: uint,
        participant-role: (string-ascii 20),
        accumulated-earnings: uint
    }
)

;; Track total registered songs
(define-data-var registered-song-count uint u0)

;; Track contract administrator
(define-data-var contract-administrator principal tx-sender)

;; Read-only functions
(define-read-only (get-song-information (song-identifier uint))
    (map-get? RegisteredSongs { song-identifier: song-identifier })
)

(define-read-only (get-royalty-distribution (song-identifier uint) (royalty-recipient principal))
    (map-get? RoyaltyDistribution { song-identifier: song-identifier, royalty-recipient: royalty-recipient })
)

(define-read-only (get-total-registered-songs)
    (var-get registered-song-count)
)

;; Get royalty shares for a song
(define-read-only (get-royalty-shares-by-song (song-identifier uint))
    (let (
        (song-info (get-song-information song-identifier))
        (primary-artist (match song-info record (get primary-artist record) tx-sender))
    )
    (let ((distribution (get-royalty-distribution song-identifier primary-artist)))
        (match distribution share
            (list {
                royalty-recipient: primary-artist,
                royalty-percentage: (get royalty-percentage share)
            })
            (list))))
)

;; Helper functions for input validation
(define-private (is-valid-royalty-share (share {
    royalty-percentage: uint,
    participant-role: (string-ascii 20),
    accumulated-earnings: uint
}))
    (> (get royalty-percentage share) u0)
)

(define-private (verify-contract-administrator)
    (is-eq tx-sender (var-get contract-administrator))
)

(define-private (validate-royalty-percentage (royalty-percentage uint))
    (and (>= royalty-percentage u0) (<= royalty-percentage u100))
)

(define-private (validate-string-ascii (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-principal (principal-to-check principal))
    (and 
        (not (is-eq principal-to-check tx-sender))  ;; Can't be the sender
        (not (is-eq principal-to-check (var-get contract-administrator)))  ;; Can't be the admin
    ))

;; Fixed process-royalty-share function
(define-private (process-royalty-share
    (share {royalty-recipient: principal, royalty-percentage: uint}) 
    (payment-amount uint))
    (let (
        (recipient-payment-amount (/ (* payment-amount (get royalty-percentage share)) u100))
    )
    (if (> recipient-payment-amount u0)
        (match (stx-transfer? recipient-payment-amount tx-sender (get royalty-recipient share))
            success payment-amount
            error u0)
        u0))
)

;; Updated distribute-royalty-payment
(define-private (distribute-royalty-payment (song-identifier uint) (payment-amount uint))
    (let (
        (royalty-distribution-list (get-royalty-shares-by-song song-identifier))
        (total-distributed (fold process-royalty-share 
                               royalty-distribution-list 
                               payment-amount))
    )
    (begin
        (asserts! (> (len royalty-distribution-list) u0) ERR-SONG-DOES-NOT-EXIST)
        (asserts! (> total-distributed u0) ERR-PAYMENT-FAILED)
        (ok total-distributed)))
)

;; Public functions with added input validation
(define-public (register-new-song (song-title (string-ascii 50)) (primary-artist principal))
    (let (
        (new-song-identifier (+ (var-get registered-song-count) u1))
    )
    (begin
        (asserts! (verify-contract-administrator) ERR-UNAUTHORIZED-ACCESS)
        (asserts! (validate-string-ascii song-title) ERR-INVALID-SONG-TITLE)
        (asserts! (validate-principal primary-artist) ERR-INVALID-PRIMARY-ARTIST)
        
        (map-set RegisteredSongs
            { song-identifier: new-song-identifier }
            {
                song-title: song-title,
                primary-artist: primary-artist,
                accumulated-revenue: u0,
                publication-date: stacks-block-height,
                song-status-active: true
            }
        )
        (var-set registered-song-count new-song-identifier)
        (ok new-song-identifier)))
)

(define-public (set-royalty-distribution 
    (song-identifier uint) 
    (royalty-recipient principal) 
    (royalty-percentage uint) 
    (participant-role (string-ascii 20)))
    (let (
        (song-record (get-song-information song-identifier))
    )
    (begin
        (asserts! (is-some song-record) ERR-SONG-DOES-NOT-EXIST)
        (asserts! (validate-royalty-percentage royalty-percentage) ERR-INVALID-ROYALTY-PERCENTAGE)
        (asserts! (validate-participant-role participant-role) ERR-INVALID-PARTICIPANT-ROLE)
        (asserts! (validate-principal royalty-recipient) ERR-INVALID-ROYALTY-RECIPIENT)
        
        (map-set RoyaltyDistribution
            { song-identifier: song-identifier, royalty-recipient: royalty-recipient }
            {
                royalty-percentage: royalty-percentage,
                participant-role: participant-role,
                accumulated-earnings: u0
            }
        )
        (ok true)))
)

(define-public (process-royalty-payment (song-identifier uint) (royalty-payment-amount uint))
    (let (
        (song-record (get-song-information song-identifier))
    )
    (begin
        (asserts! (is-some song-record) ERR-SONG-DOES-NOT-EXIST)
        (asserts! (>= (stx-get-balance tx-sender) royalty-payment-amount) ERR-INSUFFICIENT-PAYMENT-FUNDS)
        
        (try! (distribute-royalty-payment song-identifier royalty-payment-amount))
        (map-set RegisteredSongs
            { song-identifier: song-identifier }
            (merge (unwrap-panic song-record)
                { accumulated-revenue: (+ (get accumulated-revenue (unwrap-panic song-record)) royalty-payment-amount) }
            )
        )
        (ok true)))
)

(define-public (update-song-active-status (song-identifier uint) (new-active-status bool))
    (let (
        (song-record (get-song-information song-identifier))
    )
    (begin
        (asserts! (verify-contract-administrator) ERR-UNAUTHORIZED-ACCESS)
        (asserts! (is-some song-record) ERR-SONG-DOES-NOT-EXIST)
        
        (map-set RegisteredSongs
            { song-identifier: song-identifier }
            (merge (unwrap-panic song-record)
                { song-status-active: new-active-status }
            )
        )
        (ok true)))
)

(define-public (transfer-administrator-rights (new-administrator principal))
    (begin
        (asserts! (verify-contract-administrator) ERR-UNAUTHORIZED-ACCESS)
        (asserts! (validate-principal new-administrator) ERR-INVALID-ADMINISTRATOR)
        
        (var-set contract-administrator new-administrator)
        (ok true))
)

;; Contract initialization
(begin
    (var-set registered-song-count u0))

Functions (16)

FunctionAccessArgs
get-song-informationread-onlysong-identifier: uint
get-royalty-distributionread-onlysong-identifier: uint, royalty-recipient: principal
get-total-registered-songsread-only
get-royalty-shares-by-songread-onlysong-identifier: uint
verify-contract-administratorprivate
validate-royalty-percentageprivateroyalty-percentage: uint
validate-string-asciiprivateinput: (string-ascii 50
validate-participant-roleprivaterole: (string-ascii 20
validate-principalprivateprincipal-to-check: principal
process-royalty-shareprivateshare: {royalty-recipient: principal, royalty-percentage: uint}, payment-amount: uint
distribute-royalty-paymentprivatesong-identifier: uint, payment-amount: uint
register-new-songpublicsong-title: (string-ascii 50
set-royalty-distributionpublicsong-identifier: uint, royalty-recipient: principal, royalty-percentage: uint, participant-role: (string-ascii 20
process-royalty-paymentpublicsong-identifier: uint, royalty-payment-amount: uint
update-song-active-statuspublicsong-identifier: uint, new-active-status: bool
transfer-administrator-rightspublicnew-administrator: principal