Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 103 additions & 33 deletions contracts/RightsRegistry.clar
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
;; First, let's define the SIP-010 trait
;; Rights Registry Contract
;; Handles music rights ownership, royalty splits, and rights transfers

;; Define SIP-010 trait
(define-trait sip-010-trait
(
(transfer (uint principal principal (optional (buff 34))) (response bool uint))
Expand All @@ -11,8 +14,17 @@
)
)

;; Rights Registry Contract
;; Handles music rights ownership, royalty splits, and rights transfers
;; Constants
(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-INVALID-SONG (err u101))
(define-constant ERR-ALREADY-EXISTS (err u102))
(define-constant ERR-INVALID-SHARE (err u103))
(define-constant ERR-INVALID-SONG-ID (err u104))
(define-constant ERR-INVALID-TITLE (err u105))
(define-constant ERR-INVALID-STATUS (err u106))
(define-constant ERR-INVALID-ROLE (err u107))
(define-constant ERR-ZERO-ADDRESS (err u108))
(define-constant ERR-TOTAL-SHARE-EXCEEDED (err u109))

;; Data Variables
(define-data-var contract-owner principal tx-sender)
Expand All @@ -36,28 +48,40 @@
}
)

;; Constants
(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-INVALID-SONG (err u101))
(define-constant ERR-ALREADY-EXISTS (err u102))
(define-constant ERR-INVALID-SHARE (err u103))
(define-map total-song-shares
{ song-id: uint }
{ total-share: uint }
)

;; Read-Only Functions
(define-read-only (get-song-details (song-id uint))
(map-get? rights-registry { song-id: song-id })
(begin
(asserts! (> song-id u0) ERR-INVALID-SONG-ID)
(ok (map-get? rights-registry { song-id: song-id }))
)
)

(define-read-only (get-collaborator-share (song-id uint) (collaborator principal))
(map-get? royalty-splits { song-id: song-id, collaborator: collaborator })
(begin
(asserts! (> song-id u0) ERR-INVALID-SONG-ID)
(ok (map-get? royalty-splits { song-id: song-id, collaborator: collaborator }))
)
)

;; Public Functions
(define-public (register-song (song-id uint) (title (string-ascii 256)))
(let
((song-exists (map-get? rights-registry { song-id: song-id })))
(begin
;; Input validation
(asserts! (> song-id u0) ERR-INVALID-SONG-ID)
(asserts! (not (is-eq title "")) ERR-INVALID-TITLE)

;; Authorization check
(asserts! (is-eq tx-sender (var-get contract-owner)) ERR-NOT-AUTHORIZED)
(asserts! (is-none song-exists) ERR-ALREADY-EXISTS)

;; Check if song exists
(asserts! (is-none (map-get? rights-registry { song-id: song-id })) ERR-ALREADY-EXISTS)

;; Register song
(map-set rights-registry
{ song-id: song-id }
{
Expand All @@ -67,6 +91,13 @@
status: "active"
}
)

;; Initialize total share
(map-set total-song-shares
{ song-id: song-id }
{ total-share: u0 }
)

(ok true)
)
)
Expand All @@ -76,41 +107,80 @@
(collaborator principal)
(share uint)
(role (string-ascii 20)))
(let
((song-exists (map-get? rights-registry { song-id: song-id })))

;; Validations
(asserts! (is-some song-exists) ERR-INVALID-SONG)
(asserts! (is-eq tx-sender (get owner (unwrap-panic song-exists))) ERR-NOT-AUTHORIZED)
(asserts! (<= share u10000) ERR-INVALID-SHARE) ;; Max 100%
(begin
;; Input validation
(asserts! (> song-id u0) ERR-INVALID-SONG-ID)
(asserts! (not (is-eq collaborator tx-sender)) ERR-ZERO-ADDRESS)
(asserts! (<= share u10000) ERR-INVALID-SHARE)
(asserts!
(or
(is-eq role "writer")
(is-eq role "producer")
(is-eq role "performer")
)
ERR-INVALID-ROLE
)

(map-set royalty-splits
{ song-id: song-id, collaborator: collaborator }
{ share: share, role: role }
;; Get song details and validate
(let (
(song-exists (unwrap! (get-song-details song-id) ERR-INVALID-SONG))
(current-shares (default-to { total-share: u0 }
(map-get? total-song-shares { song-id: song-id })))
)

(asserts! (is-some song-exists) ERR-INVALID-SONG)
(asserts! (is-eq tx-sender (get owner (unwrap! song-exists ERR-INVALID-SONG))) ERR-NOT-AUTHORIZED)

;; Check if total share would exceed 100%
(asserts! (<= (+ share (get total-share current-shares)) u10000) ERR-TOTAL-SHARE-EXCEEDED)

;; Update collaborator share
(map-set royalty-splits
{ song-id: song-id, collaborator: collaborator }
{ share: share, role: role }
)

;; Update total share
(map-set total-song-shares
{ song-id: song-id }
{ total-share: (+ share (get total-share current-shares)) }
)

(ok true)
)
(ok true)
)
)

(define-public (update-song-status (song-id uint) (new-status (string-ascii 10)))
(let
((song-exists (map-get? rights-registry { song-id: song-id })))

(asserts! (is-some song-exists) ERR-INVALID-SONG)
(asserts! (is-eq tx-sender (get owner (unwrap-panic song-exists))) ERR-NOT-AUTHORIZED)
(begin
;; Input validation
(asserts! (> song-id u0) ERR-INVALID-SONG-ID)
(asserts!
(or
(is-eq new-status "active")
(is-eq new-status "inactive")
)
ERR-INVALID-STATUS
)

(map-set rights-registry
{ song-id: song-id }
(merge (unwrap-panic song-exists) { status: new-status })
(let ((song-exists (unwrap! (get-song-details song-id) ERR-INVALID-SONG)))
(asserts! (is-some song-exists) ERR-INVALID-SONG)
(asserts! (is-eq tx-sender (get owner (unwrap! song-exists ERR-INVALID-SONG))) ERR-NOT-AUTHORIZED)

(map-set rights-registry
{ song-id: song-id }
(merge (unwrap! song-exists ERR-INVALID-SONG) { status: new-status })
)
(ok true)
)
(ok true)
)
)

;; Administrative Functions
(define-public (transfer-ownership (new-owner principal))
(begin
(asserts! (is-eq tx-sender (var-get contract-owner)) ERR-NOT-AUTHORIZED)
(asserts! (not (is-eq new-owner tx-sender)) ERR-ZERO-ADDRESS)
(var-set contract-owner new-owner)
(ok true)
)
Expand Down