Source Code

(define-non-fungible-token emoji-nft uint)

(define-map emotes
    { nft-contract: principal, token-id: uint, emoji: (string-utf8 10) }
    (list 100 principal)
)

(define-map emote-count
    { nft-contract: principal, token-id: uint, emoji: (string-utf8 10) }
    uint
)

(define-map user-emotes
    { user: principal, nft-contract: principal, token-id: uint }
    (list 20 (string-utf8 10))
)

(define-constant err-already-emoted (err u100))
(define-constant err-invalid-emoji (err u101))
(define-constant err-max-emotes (err u102))
(define-constant err-invalid-signature (err u103))

(define-read-only (get-emote-count (nft-contract principal) (token-id uint) (emoji (string-utf8 10)))
    (ok (default-to u0 (map-get? emote-count { nft-contract: nft-contract, token-id: token-id, emoji: emoji })))
)

(define-read-only (get-emotes (nft-contract principal) (token-id uint) (emoji (string-utf8 10)))
    (ok (map-get? emotes { nft-contract: nft-contract, token-id: token-id, emoji: emoji }))
)

(define-read-only (get-user-emotes (user principal) (nft-contract principal) (token-id uint))
    (ok (map-get? user-emotes { user: user, nft-contract: nft-contract, token-id: token-id }))
)

(define-read-only (has-emoted (user principal) (nft-contract principal) (token-id uint) (emoji (string-utf8 10)))
    (match (map-get? user-emotes { user: user, nft-contract: nft-contract, token-id: token-id })
        user-emoji-list (ok (is-some (index-of user-emoji-list emoji)))
        (ok false)
    )
)

(define-public (emote (nft-contract principal) (token-id uint) (emoji (string-utf8 10)))
    (let
        (
            (current-emotes (default-to (list) (map-get? emotes { nft-contract: nft-contract, token-id: token-id, emoji: emoji })))
            (current-count (default-to u0 (map-get? emote-count { nft-contract: nft-contract, token-id: token-id, emoji: emoji })))
            (user-emoji-list (default-to (list) (map-get? user-emotes { user: tx-sender, nft-contract: nft-contract, token-id: token-id })))
        )
        (asserts! (> (len emoji) u0) err-invalid-emoji)
        (asserts! (is-none (index-of user-emoji-list emoji)) err-already-emoted)
        (asserts! (< (len current-emotes) u100) err-max-emotes)
        (map-set emotes { nft-contract: nft-contract, token-id: token-id, emoji: emoji }
            (unwrap-panic (as-max-len? (append current-emotes tx-sender) u100))
        )
        (map-set emote-count { nft-contract: nft-contract, token-id: token-id, emoji: emoji }
            (+ current-count u1)
        )
        (map-set user-emotes { user: tx-sender, nft-contract: nft-contract, token-id: token-id }
            (unwrap-panic (as-max-len? (append user-emoji-list emoji) u20))
        )
        (ok true)
    )
)

(define-public (remove-emote (nft-contract principal) (token-id uint) (emoji (string-utf8 10)))
    (let
        (
            (current-count (default-to u0 (map-get? emote-count { nft-contract: nft-contract, token-id: token-id, emoji: emoji })))
            (user-emoji-list (default-to (list) (map-get? user-emotes { user: tx-sender, nft-contract: nft-contract, token-id: token-id })))
        )
        (asserts! (is-some (index-of user-emoji-list emoji)) err-already-emoted)
        (map-set emote-count { nft-contract: nft-contract, token-id: token-id, emoji: emoji }
            (if (> current-count u0) (- current-count u1) u0)
        )
        (ok true)
    )
)

Functions (6)

FunctionAccessArgs
get-emote-countread-onlynft-contract: principal, token-id: uint, emoji: (string-utf8 10
get-emotesread-onlynft-contract: principal, token-id: uint, emoji: (string-utf8 10
get-user-emotesread-onlyuser: principal, nft-contract: principal, token-id: uint
has-emotedread-onlyuser: principal, nft-contract: principal, token-id: uint, emoji: (string-utf8 10
emotepublicnft-contract: principal, token-id: uint, emoji: (string-utf8 10
remove-emotepublicnft-contract: principal, token-id: uint, emoji: (string-utf8 10