diff --git a/README.md b/README.md index 51fa074..72483fc 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,36 @@ # Intellectual Property Protection Smart Contract -This project implements a smart contract for intellectual property (IP) protection using Clarity, the smart contract language for the Stacks blockchain. The contract allows users to register, verify, and transfer ownership of intellectual property. +This project implements a smart contract for intellectual property (IP) protection using Clarity, the smart contract language for the Stacks blockchain. The contract allows users to register, verify, transfer ownership, set expirations, and verify ownership for intellectual property. ## Features -- Register new intellectual property by providing a hash of the work -- Check ownership of registered intellectual property -- Verify the hash of registered intellectual property -- Transfer ownership of registered intellectual property +* Register new intellectual property by providing a hash of the work and an optional expiration date +* Check ownership of registered intellectual property +* Verify the hash of registered intellectual property +* Transfer ownership of registered intellectual property +* Extend the registration period of intellectual property +* Automatic expiration of IP registrations +* Verify the current owner of a specific IP ID (new feature) ## Smart Contract Overview The main components of the smart contract are: 1. **Data Storage** - - `owner`: Stores the contract owner's principal (address) - - `ip-registrations`: A map that stores IP registrations, indexed by an IP ID - - `ip-counter`: A counter to generate unique IP IDs + * `owner`: Stores the contract owner's principal (address) + * `ip-registrations`: A map that stores IP registrations, indexed by an IP ID + * `registered-hashes`: A map that tracks registered hashes to prevent duplicates + * `ip-counter`: A counter to generate unique IP IDs 2. **Main Functions** - - `register-ip`: Register new IP by providing a hash of the work - - `check-ip-ownership`: Check the ownership of a registered IP - - `verify-ip-hash`: Verify an IP hash against the registered hash - - `transfer-ip`: Transfer ownership of an IP to another address + * `register-ip`: Register new IP by providing a hash of the work and an optional expiration date + * `check-ip-ownership`: Check the ownership of a registered IP + * `verify-ip-hash`: Verify an IP hash against the registered hash + * `transfer-ip`: Transfer ownership of an IP to another address + * `extend-ip-registration`: Extend the registration period of an IP + * `is-hash-registered`: Check if a hash is already registered + * `update-ip-metadata`: Update the hash of an existing IP registration + * `verify-ip-owner`: Verify the current owner of a specific IP ID (new function) ## Usage @@ -35,17 +43,19 @@ To use this smart contract, you need to: To register new intellectual property: -```clarity -(contract-call? .ip-protection-contract register-ip 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef) +```lisp +(contract-call? .ip-protection-contract register-ip + 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef + (some u144000)) ``` -This will return the new IP ID. +This will register the IP with the given hash and set an expiration 144000 blocks in the future. Omit the second argument or use `none` to register without an expiration date. ### Checking IP Ownership To check the ownership of a registered IP: -```clarity +```lisp (contract-call? .ip-protection-contract check-ip-ownership u1) ``` @@ -55,8 +65,9 @@ Replace `u1` with the IP ID you want to check. To verify the hash of a registered IP: -```clarity -(contract-call? .ip-protection-contract verify-ip-hash u1 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef) +```lisp +(contract-call? .ip-protection-contract verify-ip-hash u1 + 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef) ``` Replace `u1` with the IP ID and provide the hash you want to verify. @@ -65,12 +76,44 @@ Replace `u1` with the IP ID and provide the hash you want to verify. To transfer ownership of an IP: -```clarity -(contract-call? .ip-protection-contract transfer-ip u1 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7) +```lisp +(contract-call? .ip-protection-contract transfer-ip u1 + 'SP2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKNRV9EJ7) ``` Replace `u1` with the IP ID and provide the principal of the new owner. +### Extending IP Registration + +To extend the registration period of an IP: + +```lisp +(contract-call? .ip-protection-contract extend-ip-registration u1 u288000) +``` + +Replace `u1` with the IP ID and provide the new expiration block height. + +### Updating IP Metadata + +To update the hash of an existing IP registration: + +```lisp +(contract-call? .ip-protection-contract update-ip-metadata u1 + 0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba) +``` + +Replace `u1` with the IP ID and provide the new hash. + +### Verifying IP Owner + +To verify the current owner of a specific IP ID: + +```lisp +(contract-call? .ip-protection-contract verify-ip-owner u1) +``` + +Replace `u1` with the IP ID you want to verify. This function returns the current owner and expiration date (if set) for the specified IP ID. + ## Development To further develop or modify this smart contract: @@ -80,6 +123,16 @@ To further develop or modify this smart contract: 3. Test thoroughly using Clarity testing frameworks 4. Deploy the updated contract to the Stacks blockchain +## Safety Features + +The contract includes several safety checks: + +* Validation of IP hash length and content +* Prevention of duplicate hash registrations +* Expiration date checks to ensure they are set in the future +* Ownership checks for transfers and registration extensions +* Input validation for IP IDs to ensure they are within valid range + ## Author Blessing Eze \ No newline at end of file diff --git a/contracts/shield.clar b/contracts/shield.clar index 16bd048..80eae2c 100644 --- a/contracts/shield.clar +++ b/contracts/shield.clar @@ -1,5 +1,4 @@ -;; Smart Contract on Intellectual Property Protection - +;; Smart Contract on Intellectual Property Protection with Expiration Date, Corrected Safety Checks, IP Update Functionality, Owner Verification, and Optimized Expiration Extension ;; Define error codes (define-constant ERR-NOT-AUTHORIZED (err u1000)) (define-constant ERR-INVALID-HASH-LENGTH (err u1001)) @@ -8,6 +7,9 @@ (define-constant ERR-IP-NOT-FOUND (err u1004)) (define-constant ERR-INVALID-IP-ID (err u1005)) (define-constant ERR-IP-ID-OUT-OF-RANGE (err u1006)) +(define-constant ERR-IP-EXPIRED (err u1007)) +(define-constant ERR-INVALID-EXPIRATION (err u1008)) +(define-constant ERR-NO-EXPIRATION-SET (err u1009)) ;; Define the contract (define-data-var owner principal tx-sender) @@ -15,7 +17,7 @@ ;; Define a map to store IP registrations (define-map ip-registrations { ip-id: uint } - { owner: principal, timestamp: uint, hash: (buff 32) } + { owner: principal, timestamp: uint, hash: (buff 32), expiration: (optional uint) } ) ;; Define a map to track registered hashes @@ -28,20 +30,27 @@ (define-data-var ip-counter uint u0) ;; Function to register new IP -(define-public (register-ip (ip-hash (buff 32))) +(define-public (register-ip (ip-hash (buff 32)) (expiration-block (optional uint))) (let ( (new-id (+ (var-get ip-counter) u1)) + (current-block block-height) ) ;; Perform input validation (asserts! (is-eq (len ip-hash) u32) ERR-INVALID-HASH-LENGTH) (asserts! (not (is-eq ip-hash 0x0000000000000000000000000000000000000000000000000000000000000000)) ERR-HASH-ALL-ZEROS) (asserts! (is-none (map-get? registered-hashes { hash: ip-hash })) ERR-HASH-ALREADY-REGISTERED) + ;; Check expiration validity + (asserts! (match expiration-block + expiration (> expiration current-block) + true + ) + ERR-INVALID-EXPIRATION) ;; Register the IP (map-set ip-registrations { ip-id: new-id } - { owner: tx-sender, timestamp: block-height, hash: ip-hash } + { owner: tx-sender, timestamp: current-block, hash: ip-hash, expiration: expiration-block } ) ;; Track the registered hash (map-set registered-hashes @@ -60,7 +69,19 @@ (ip-data (map-get? ip-registrations { ip-id: ip-id })) ) (if (is-some ip-data) - (ok (get owner (unwrap-panic ip-data))) + (let + ( + (unwrapped-ip-data (unwrap-panic ip-data)) + (current-block block-height) + ) + (if (and + (is-some (get expiration unwrapped-ip-data)) + (>= current-block (unwrap-panic (get expiration unwrapped-ip-data))) + ) + ERR-IP-EXPIRED + (ok (get owner unwrapped-ip-data)) + ) + ) ERR-IP-NOT-FOUND ) ) @@ -73,7 +94,19 @@ (ip-data (map-get? ip-registrations { ip-id: ip-id })) ) (if (is-some ip-data) - (ok (is-eq (get hash (unwrap-panic ip-data)) hash-to-verify)) + (let + ( + (unwrapped-ip-data (unwrap-panic ip-data)) + (current-block block-height) + ) + (if (and + (is-some (get expiration unwrapped-ip-data)) + (>= current-block (unwrap-panic (get expiration unwrapped-ip-data))) + ) + ERR-IP-EXPIRED + (ok (is-eq (get hash unwrapped-ip-data) hash-to-verify)) + ) + ) ERR-IP-NOT-FOUND ) ) @@ -97,8 +130,15 @@ (let ( (unwrapped-ip-data (unwrap-panic ip-data)) + (current-block block-height) ) (asserts! (is-eq tx-sender (get owner unwrapped-ip-data)) ERR-NOT-AUTHORIZED) + (asserts! (or + (is-none (get expiration unwrapped-ip-data)) + (< current-block (unwrap-panic (get expiration unwrapped-ip-data))) + ) + ERR-IP-EXPIRED + ) (map-set ip-registrations { ip-id: ip-id } (merge unwrapped-ip-data { owner: new-owner }) @@ -112,4 +152,134 @@ ;; Function to check if a hash is already registered (define-read-only (is-hash-registered (ip-hash (buff 32))) (is-some (map-get? registered-hashes { hash: ip-hash })) +) + +;; Smart Contract on Intellectual Property Protection with Expiration Date, Corrected Safety Checks, IP Update Functionality, Owner Verification, and Corrected Expiration Extension + +;; function to extend IP registration +(define-public (extend-ip-registration (ip-id uint) (new-expiration uint)) + (let + ( + (current-ip-counter (var-get ip-counter)) + (current-block block-height) + ) + ;; Perform input validation + (asserts! (<= ip-id current-ip-counter) ERR-IP-ID-OUT-OF-RANGE) + (asserts! (> ip-id u0) ERR-INVALID-IP-ID) + (asserts! (> new-expiration current-block) ERR-INVALID-EXPIRATION) + + (let + ( + (ip-data (map-get? ip-registrations { ip-id: ip-id })) + ) + (asserts! (is-some ip-data) ERR-IP-NOT-FOUND) + (let + ( + (unwrapped-ip-data (unwrap-panic ip-data)) + ) + (asserts! (is-eq tx-sender (get owner unwrapped-ip-data)) ERR-NOT-AUTHORIZED) + (match (get expiration unwrapped-ip-data) + current-expiration (if (> new-expiration current-expiration) + (begin + (map-set ip-registrations + { ip-id: ip-id } + (merge unwrapped-ip-data { expiration: (some new-expiration) }) + ) + (ok true) + ) + ERR-INVALID-EXPIRATION) + (begin + (map-set ip-registrations + { ip-id: ip-id } + (merge unwrapped-ip-data { expiration: (some new-expiration) }) + ) + (ok true) + ) + ) + ) + ) + ) +) + +;; Function to update IP metadata (hash) +(define-public (update-ip-metadata (ip-id uint) (new-hash (buff 32))) + (let + ( + (current-ip-counter (var-get ip-counter)) + ) + ;; Perform input validation + (asserts! (<= ip-id current-ip-counter) ERR-IP-ID-OUT-OF-RANGE) + (asserts! (> ip-id u0) ERR-INVALID-IP-ID) + (asserts! (is-eq (len new-hash) u32) ERR-INVALID-HASH-LENGTH) + (asserts! (not (is-eq new-hash 0x0000000000000000000000000000000000000000000000000000000000000000)) ERR-HASH-ALL-ZEROS) + + (let + ( + (ip-data (map-get? ip-registrations { ip-id: ip-id })) + ) + (asserts! (is-some ip-data) ERR-IP-NOT-FOUND) + (let + ( + (unwrapped-ip-data (unwrap-panic ip-data)) + (current-block block-height) + ) + ;; Check if the caller is the current owner + (asserts! (is-eq tx-sender (get owner unwrapped-ip-data)) ERR-NOT-AUTHORIZED) + ;; Check if the IP has not expired + (asserts! (or + (is-none (get expiration unwrapped-ip-data)) + (< current-block (unwrap-panic (get expiration unwrapped-ip-data))) + ) + ERR-IP-EXPIRED + ) + ;; Remove the old hash from registered-hashes + (map-delete registered-hashes { hash: (get hash unwrapped-ip-data) }) + ;; Update the IP registration with the new hash + (map-set ip-registrations + { ip-id: ip-id } + (merge unwrapped-ip-data { hash: new-hash }) + ) + ;; Add the new hash to registered-hashes + (map-set registered-hashes + { hash: new-hash } + { ip-id: ip-id } + ) + (ok true) + ) + ) + ) +) + +;; Function to verify the current owner of a specific IP ID +(define-read-only (verify-ip-owner (ip-id uint)) + (let + ( + (current-ip-counter (var-get ip-counter)) + ) + ;; Perform input validation + (asserts! (<= ip-id current-ip-counter) ERR-IP-ID-OUT-OF-RANGE) + (asserts! (> ip-id u0) ERR-INVALID-IP-ID) + + (let + ( + (ip-data (map-get? ip-registrations { ip-id: ip-id })) + ) + (if (is-some ip-data) + (let + ( + (unwrapped-ip-data (unwrap-panic ip-data)) + (current-block block-height) + ) + (if (and + (is-some (get expiration unwrapped-ip-data)) + (>= current-block (unwrap-panic (get expiration unwrapped-ip-data))) + ) + ERR-IP-EXPIRED + (ok { owner: (get owner unwrapped-ip-data), expiration: (get expiration unwrapped-ip-data) }) + ) + ) + ERR-IP-NOT-FOUND + ) + ) + ) ) \ No newline at end of file