Source Code


;; nova-fractional-shares.clar
;; Wraps an NFT and issues fungible tokens representing shares.
;; CLARITY VERSION: 2

(use-trait nova-trait-non-fungible .nova-trait-non-fungible.nova-trait-non-fungible)
(impl-trait .nova-trait-fungible.nova-trait-fungible)

(define-fungible-token share-token)

(define-data-var locked-nft (optional {contract: principal, id: uint}) none)
(define-constant ERR-ALREADY-LOCKED (err u100))
(define-constant ERR-NOT-LOCKED (err u101))

;; Lock NFT to mint shares
(define-public (lock-nft (token-trait <nova-trait-non-fungible>) (token-id uint) (share-supply uint))
    (let (
        (sender tx-sender)
    )
    (asserts! (is-none (var-get locked-nft)) ERR-ALREADY-LOCKED)
    
    (try! (contract-call? token-trait transfer token-id sender (as-contract tx-sender)))
    
    (var-set locked-nft (some {contract: (contract-of token-trait), id: token-id}))
    (try! (ft-mint? share-token share-supply sender))
    (ok true))
)

;; Redeem shares to unlock NFT (only if you hold ALL shares)
;; This is a simplified logic where 100% shares required to unlock.
(define-public (redeem-nft (token-trait <nova-trait-non-fungible>))
    (let (
        (sender tx-sender)
        (locked (unwrap! (var-get locked-nft) ERR-NOT-LOCKED))
        (total (ft-get-supply share-token))
    )
    (asserts! (is-eq (contract-of token-trait) (get contract locked)) (err u102))
    
    ;; Burn all tokens (check balance == total supply)
    (asserts! (is-eq (ft-get-balance share-token sender) total) (err u103))
    (try! (ft-burn? share-token total sender))

    (try! (as-contract (contract-call? token-trait transfer (get id locked) tx-sender sender)))
    (var-set locked-nft none)
    (ok true))
)

;; SIP-010 / Nova Trait Fungible Interface

(define-read-only (get-total-supply)
    (ok (ft-get-supply share-token))
)

(define-read-only (get-name)
    (ok "Fractional Share")
)

(define-read-only (get-symbol)
    (ok "F-NFT")
)

(define-read-only (get-decimals)
    (ok u0)
)

(define-read-only (get-balance (account principal))
    (ok (ft-get-balance share-token account))
)

(define-read-only (get-token-uri)
    (ok none)
)

(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
    (begin
        (asserts! (is-eq tx-sender sender) (err u4))
        (match (ft-transfer? share-token amount sender recipient)
            response (begin
                (print memo)
                (ok response)
            )
            error (err error)
        )
    )
)

Functions (9)

FunctionAccessArgs
lock-nftpublictoken-trait: <nova-trait-non-fungible>, token-id: uint, share-supply: uint
redeem-nftpublictoken-trait: <nova-trait-non-fungible>
get-total-supplyread-only
get-nameread-only
get-symbolread-only
get-decimalsread-only
get-balanceread-onlyaccount: principal
get-token-uriread-only
transferpublicamount: uint, sender: principal, recipient: principal, memo: (optional (buff 34