Source Code

;; profile-registry.clar
;; User profile management system

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-already-exists (err u102))
(define-constant err-invalid-name (err u103))

;; Data Maps
(define-map profiles
    { user: principal }
    {
        username: (string-ascii 48),
        bio: (string-utf8 256),
        avatar-url: (string-ascii 256),
        created-at: uint,
        updated-at: uint,
        reputation: uint,
        is-verified: bool,
    }
)

(define-map username-registry
    { username: (string-ascii 48) }
    { owner: principal }
)
(define-map user-settings
    { user: principal }
    {
        notifications: bool,
        public-profile: bool,
        theme: (string-ascii 16),
    }
)
(define-map social-links
    { user: principal }
    {
        twitter: (string-ascii 64),
        discord: (string-ascii 64),
        website: (string-ascii 128),
    }
)

;; Variables
(define-data-var profile-count uint u0)
(define-data-var registration-fee uint u1000000)

;; Read-only functions

(define-read-only (get-profile (user principal))
    (map-get? profiles { user: user })
)

(define-read-only (get-username-owner (username (string-ascii 48)))
    (get owner (map-get? username-registry { username: username }))
)

(define-read-only (get-user-settings (user principal))
    (default-to {
        notifications: true,
        public-profile: true,
        theme: "light",
    }
        (map-get? user-settings { user: user })
    )
)

(define-read-only (get-social-links (user principal))
    (map-get? social-links { user: user })
)

(define-read-only (get-profile-count)
    (var-get profile-count)
)

(define-read-only (get-registration-fee)
    (var-get registration-fee)
)

(define-read-only (is-username-taken (username (string-ascii 48)))
    (is-some (map-get? username-registry { username: username }))
)

;; Public functions

(define-public (register-profile
        (username (string-ascii 48))
        (bio (string-utf8 256))
    )
    (begin
        (asserts! (is-none (map-get? profiles { user: tx-sender }))
            err-already-exists
        )
        (asserts! (is-none (map-get? username-registry { username: username }))
            err-already-exists
        )
        (asserts! (> (len username) u2) err-invalid-name)

        (map-set profiles { user: tx-sender } {
            username: username,
            bio: bio,
            avatar-url: "",
            created-at: burn-block-height,
            updated-at: burn-block-height,
            reputation: u0,
            is-verified: false,
        })
        (map-set username-registry { username: username } { owner: tx-sender })
        (var-set profile-count (+ (var-get profile-count) u1))
        (ok true)
    )
)

(define-public (update-bio (new-bio (string-utf8 256)))
    (match (map-get? profiles { user: tx-sender })
        profile (begin
            (map-set profiles { user: tx-sender }
                (merge profile {
                    bio: new-bio,
                    updated-at: burn-block-height,
                })
            )
            (ok true)
        )
        err-not-found
    )
)

(define-public (update-avatar (new-url (string-ascii 256)))
    (match (map-get? profiles { user: tx-sender })
        profile (begin
            (map-set profiles { user: tx-sender }
                (merge profile {
                    avatar-url: new-url,
                    updated-at: burn-block-height,
                })
            )
            (ok true)
        )
        err-not-found
    )
)

(define-public (set-user-settings
        (notifications bool)
        (public-profile bool)
        (theme (string-ascii 16))
    )
    (begin
        (map-set user-settings { user: tx-sender } {
            notifications: notifications,
            public-profile: public-profile,
            theme: theme,
        })
        (ok true)
    )
)

(define-public (update-social-links
        (twitter (string-ascii 64))
        (discord (string-ascii 64))
        (website (string-ascii 128))
    )
    (begin
        (map-set social-links { user: tx-sender } {
            twitter: twitter,
            discord: discord,
            website: website,
        })
        (ok true)
    )
)

(define-public (verify-user (user principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? profiles { user: user })
            profile (begin
                (map-set profiles { user: user }
                    (merge profile { is-verified: true })
                )
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (unverify-user (user principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? profiles { user: user })
            profile (begin
                (map-set profiles { user: user }
                    (merge profile { is-verified: false })
                )
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (add-reputation
        (user principal)
        (amount uint)
    )
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? profiles { user: user })
            profile (begin
                (map-set profiles { user: user }
                    (merge profile { reputation: (+ (get reputation profile) amount) })
                )
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (slash-reputation
        (user principal)
        (amount uint)
    )
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? profiles { user: user })
            profile (begin
                (let ((current-rep (get reputation profile)))
                    (map-set profiles { user: user }
                        (merge profile { reputation: (if (> current-rep amount)
                            (- current-rep amount)
                            u0
                        ) }
                        ))
                    (ok true)
                )
            )
            err-not-found
        )
    )
)

(define-public (set-registration-fee (new-fee uint))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (var-set registration-fee new-fee)
        (ok true)
    )
)

;; Helper functions for quota

(define-public (get-user-reputation (user principal))
    (match (map-get? profiles { user: user })
        profile (ok (get reputation profile))
        err-not-found
    )
)

(define-public (is-user-verified (user principal))
    (match (map-get? profiles { user: user })
        profile (ok (get is-verified profile))
        err-not-found
    )
)

(define-public (get-user-theme (user principal))
    (ok (get theme (get-user-settings user)))
)

(define-public (has-public-profile (user principal))
    (ok (get public-profile (get-user-settings user)))
)

(define-public (wants-notifications (user principal))
    (ok (get notifications (get-user-settings user)))
)

(define-public (get-twitter-link (user principal))
    (match (map-get? social-links { user: user })
        links (ok (get twitter links))
        (ok "")
    )
)

(define-public (get-discord-link (user principal))
    (match (map-get? social-links { user: user })
        links (ok (get discord links))
        (ok "")
    )
)

(define-public (get-website-link (user principal))
    (match (map-get? social-links { user: user })
        links (ok (get website links))
        (ok "")
    )
)

(define-public (delete-profile)
    (match (map-get? profiles { user: tx-sender })
        profile (begin
            (map-delete profiles { user: tx-sender })
            (map-delete username-registry { username: (get username profile) })
            (var-set profile-count (- (var-get profile-count) u1))
            (ok true)
        )
        err-not-found
    )
)

(define-public (admin-delete-profile (user principal))
    (begin
        (asserts! (is-eq tx-sender contract-owner) err-owner-only)
        (match (map-get? profiles { user: user })
            profile (begin
                (map-delete profiles { user: user })
                (map-delete username-registry { username: (get username profile) })
                (var-set profile-count (- (var-get profile-count) u1))
                (ok true)
            )
            err-not-found
        )
    )
)

(define-public (check-username-length (username (string-ascii 48)))
    (ok (len username))
)

(define-public (is-long-bio (user principal))
    (match (map-get? profiles { user: user })
        profile (ok (> (len (get bio profile)) u100))
        err-not-found
    )
)

(define-public (is-new-user (user principal))
    (match (map-get? profiles { user: user })
        profile (ok (< (- burn-block-height (get created-at profile)) u1000))
        err-not-found
    )
)

(define-public (get-account-age (user principal))
    (match (map-get? profiles { user: user })
        profile (ok (- burn-block-height (get created-at profile)))
        err-not-found
    )
)

(define-public (update-username (new-username (string-ascii 48)))
    (match (map-get? profiles { user: tx-sender })
        profile (begin
            (asserts!
                (is-none (map-get? username-registry { username: new-username }))
                err-already-exists
            )
            (map-delete username-registry { username: (get username profile) })
            (map-set username-registry { username: new-username } { owner: tx-sender })
            (map-set profiles { user: tx-sender }
                (merge profile {
                    username: new-username,
                    updated-at: burn-block-height,
                })
            )
            (ok true)
        )
        err-not-found
    )
)

(define-public (hello-world)
    (ok "Hello World")
)

(define-public (echo-string (msg (string-ascii 20)))
    (ok msg)
)

(define-public (concat-strings
        (a (string-ascii 20))
        (b (string-ascii 20))
    )
    (ok (concat a b))
)

(define-public (is-contract-owner-check)
    (ok (is-eq tx-sender contract-owner))
)

(define-public (get-block-info-time)
    ;; (ok (get-block-info? time (- burn-block-height u1)))
    (ok u0)
    ;; FIXME: get-block-info? is unresolved in Clarity 4
)

(define-public (get-block-info-header-hash)
    (ok (get-burn-block-info? header-hash (- burn-block-height u1)))
)

(define-public (get-block-info-burnchain-header-hash)
    ;; (ok (get-burn-block-info? burnchain-header-hash (- burn-block-height u1)))
    (ok none)
    ;; FIXME: burnchain-header-hash not supported in get-burn-block-info?
)

(define-public (get-block-info-id-header-hash)
    ;; (ok (get-burn-block-info? id-header-hash (- burn-block-height u1)))
    (ok none)
    ;; FIXME: id-header-hash not supported in get-burn-block-info?
)

(define-public (get-block-info-miner-address)
    ;; (ok (get-burn-block-info? miner-address (- burn-block-height u1)))
    (ok none)
    ;; FIXME: miner-address not supported in get-burn-block-info?
)

(define-public (get-block-info-vrf-seed)
    ;; (ok (get-burn-block-info? vrf-seed (- burn-block-height u1)))
    (ok none)
    ;; FIXME: vrf-seed not supported in get-burn-block-info?
)

(define-public (check-principal (p principal))
    (ok p)
)

(define-public (check-uint (u uint))
    (ok u)
)

(define-public (check-int (i int))
    (ok i)
)

(define-public (check-bool (b bool))
    (ok b)
)

(define-public (check-buff (b (buff 10)))
    (ok b)
)

(define-public (check-list (l (list 10 uint)))
    (ok l)
)

(define-public (check-tuple (t {
    a: uint,
    b: bool,
}))
    (ok t)
)

(define-public (check-optional (o (optional uint)))
    (ok o)
)

(define-public (check-response (r (response uint uint)))
    (ok r)
)

(define-public (noop)
    (ok true)
)

Functions (50)

FunctionAccessArgs
get-registration-feeread-only
get-profileread-onlyuser: principal
get-username-ownerread-onlyusername: (string-ascii 48
get-user-settingsread-onlyuser: principal
get-social-linksread-onlyuser: principal
get-profile-countread-only
is-username-takenread-onlyusername: (string-ascii 48
register-profilepublicusername: (string-ascii 48
update-biopublicnew-bio: (string-utf8 256
update-avatarpublicnew-url: (string-ascii 256
set-user-settingspublicnotifications: bool, public-profile: bool, theme: (string-ascii 16
update-social-linkspublictwitter: (string-ascii 64
verify-userpublicuser: principal
unverify-userpublicuser: principal
set-registration-feepublicnew-fee: uint
get-user-reputationpublicuser: principal
is-user-verifiedpublicuser: principal
get-user-themepublicuser: principal
has-public-profilepublicuser: principal
wants-notificationspublicuser: principal
get-twitter-linkpublicuser: principal
get-discord-linkpublicuser: principal
get-website-linkpublicuser: principal
delete-profilepublic
admin-delete-profilepublicuser: principal
check-username-lengthpublicusername: (string-ascii 48
is-long-biopublicuser: principal
is-new-userpublicuser: principal
get-account-agepublicuser: principal
update-usernamepublicnew-username: (string-ascii 48
hello-worldpublic
echo-stringpublicmsg: (string-ascii 20
concat-stringspublica: (string-ascii 20
is-contract-owner-checkpublic
get-block-info-timepublic
get-block-info-header-hashpublic
get-block-info-burnchain-header-hashpublic
get-block-info-id-header-hashpublic
get-block-info-miner-addresspublic
get-block-info-vrf-seedpublic
check-principalpublicp: principal
check-uintpublicu: uint
check-intpublici: int
check-boolpublicb: bool
check-buffpublicb: (buff 10
check-listpublicl: (list 10 uint
check-tuplepublict: { a: uint, b: bool, }
check-optionalpublico: (optional uint
check-responsepublicr: (response uint uint
nooppublic