;; Agent Registry - On-chain AI agent marketplace
;; Agents register with endpoint, capabilities, pricing.
;; Reputation is tracked per-agent: successful calls, revenue, rating.
(define-constant CONTRACT_OWNER tx-sender)
;; -- errors ---------------------------------------------
(define-constant ERR_OWNER_ONLY (err u300))
(define-constant ERR_NOT_FOUND (err u301))
(define-constant ERR_DUPLICATE (err u302))
(define-constant ERR_UNAUTHORIZED (err u303))
(define-constant ERR_INVALID_RATING (err u304))
(define-constant ERR_SELF_RATE (err u305))
(define-constant ERR_INACTIVE (err u306))
(define-constant ERR_INVALID_PRICE (err u307))
;; -- state ----------------------------------------------
(define-data-var next-agent-id uint u1)
(define-data-var total-payments uint u0)
(define-data-var total-revenue uint u0)
;; agent-id -> metadata
(define-map agents uint {
owner: principal,
name: (string-utf8 60),
endpoint: (string-ascii 200),
description: (string-utf8 280),
price-per-call: uint, ;; micro-STX (1 STX = 1_000_000)
capabilities: (string-utf8 200),
active: bool,
registered-at: uint ;; block height
})
;; owner principal -> agent-id (one agent per wallet for simplicity)
(define-map owner-index principal uint)
;; agent-id -> reputation
(define-map reputation uint {
successful-calls: uint,
failed-calls: uint,
total-revenue: uint,
rating-sum: uint, ;; sum of all ratings (1-5)
rating-count: uint ;; how many ratings given
})
;; who rated whom (prevents double-rating per caller)
(define-map rated-by { agent-id: uint, rater: principal } bool)
;; -- register agent -------------------------------------
(define-public (register-agent
(name (string-utf8 60))
(endpoint (string-ascii 200))
(description (string-utf8 280))
(price-per-call uint)
(capabilities (string-utf8 200))
)
(let ((id (var-get next-agent-id)))
(asserts! (is-none (map-get? owner-index tx-sender)) ERR_DUPLICATE)
(asserts! (> price-per-call u0) ERR_INVALID_PRICE)
(map-set agents id {
owner: tx-sender,
name: name,
endpoint: endpoint,
description: description,
price-per-call: price-per-call,
capabilities: capabilities,
active: true,
registered-at: block-height
})
(map-set owner-index tx-sender id)
(map-set reputation id {
successful-calls: u0,
failed-calls: u0,
total-revenue: u0,
rating-sum: u0,
rating-count: u0
})
(var-set next-agent-id (+ id u1))
(print { event: "agent-registered", id: id, name: name, owner: tx-sender })
(ok id)
)
)
;; -- update agent (owner only) --------------------------
(define-public (update-agent
(agent-id uint)
(endpoint (string-ascii 200))
(description (string-utf8 280))
(price-per-call uint)
(capabilities (string-utf8 200))
)
(let ((agent (unwrap! (map-get? agents agent-id) ERR_NOT_FOUND)))
(asserts! (is-eq tx-sender (get owner agent)) ERR_UNAUTHORIZED)
(asserts! (> price-per-call u0) ERR_INVALID_PRICE)
(map-set agents agent-id (merge agent {
endpoint: endpoint,
description: description,
price-per-call: price-per-call,
capabilities: capabilities
}))
(print { event: "agent-updated", id: agent-id })
(ok true)
)
)
;; -- toggle active (owner only) -------------------------
(define-public (set-agent-active (agent-id uint) (is-active bool))
(let ((agent (unwrap! (map-get? agents agent-id) ERR_NOT_FOUND)))
(asserts! (is-eq tx-sender (get owner agent)) ERR_UNAUTHORIZED)
(map-set agents agent-id (merge agent { active: is-active }))
(print { event: "agent-status", id: agent-id, active: is-active })
(ok true)
)
)
;; -- record successful call (gateway contract/admin) ----
(define-public (record-call-success (agent-id uint) (payment uint))
(let (
(rep (unwrap! (map-get? reputation agent-id) ERR_NOT_FOUND))
(agent (unwrap! (map-get? agents agent-id) ERR_NOT_FOUND))
)
;; Only the agent owner or contract owner can record
(asserts! (or (is-eq tx-sender (get owner agent))
(is-eq tx-sender CONTRACT_OWNER)) ERR_UNAUTHORIZED)
(map-set reputation agent-id (merge rep {
successful-calls: (+ (get successful-calls rep) u1),
total-revenue: (+ (get total-revenue rep) payment)
}))
(var-set total-payments (+ (var-get total-payments) u1))
(var-set total-revenue (+ (var-get total-revenue) payment))
(print { event: "call-success", agent-id: agent-id, payment: payment })
(ok true)
)
)
;; -- record failed call ---------------------------------
(define-public (record-call-failure (agent-id uint))
(let (
(rep (unwrap! (map-get? reputation agent-id) ERR_NOT_FOUND))
(agent (unwrap! (map-get? agents agent-id) ERR_NOT_FOUND))
)
(asserts! (or (is-eq tx-sender (get owner agent))
(is-eq tx-sender CONTRACT_OWNER)) ERR_UNAUTHORIZED)
(map-set reputation agent-id (merge rep {
failed-calls: (+ (get failed-calls rep) u1)
}))
(print { event: "call-failure", agent-id: agent-id })
(ok true)
)
)
;; -- rate an agent (any principal, once per agent) ------
(define-public (rate-agent (agent-id uint) (rating uint))
(let (
(agent (unwrap! (map-get? agents agent-id) ERR_NOT_FOUND))
(rep (unwrap! (map-get? reputation agent-id) ERR_NOT_FOUND))
)
(asserts! (not (is-eq tx-sender (get owner agent))) ERR_SELF_RATE)
(asserts! (and (>= rating u1) (<= rating u5)) ERR_INVALID_RATING)
(asserts! (is-none (map-get? rated-by { agent-id: agent-id, rater: tx-sender })) ERR_DUPLICATE)
(map-set rated-by { agent-id: agent-id, rater: tx-sender } true)
(map-set reputation agent-id (merge rep {
rating-sum: (+ (get rating-sum rep) rating),
rating-count: (+ (get rating-count rep) u1)
}))
(print { event: "agent-rated", agent-id: agent-id, rating: rating, rater: tx-sender })
(ok true)
)
)
;; -- read-only ------------------------------------------
(define-read-only (get-agent (agent-id uint))
(map-get? agents agent-id)
)
(define-read-only (get-agent-by-owner (owner principal))
(match (map-get? owner-index owner)
id (map-get? agents id)
none
)
)
(define-read-only (get-agent-id-by-owner (owner principal))
(map-get? owner-index owner)
)
(define-read-only (get-reputation (agent-id uint))
(map-get? reputation agent-id)
)
(define-read-only (get-agent-rating (agent-id uint))
(match (map-get? reputation agent-id)
rep (if (> (get rating-count rep) u0)
(ok { average: (/ (get rating-sum rep) (get rating-count rep)),
count: (get rating-count rep) })
(ok { average: u0, count: u0 }))
(err u301)
)
)
(define-read-only (get-total-agents)
(- (var-get next-agent-id) u1)
)
(define-read-only (get-network-stats)
{ total-agents: (- (var-get next-agent-id) u1),
total-payments: (var-get total-payments),
total-revenue: (var-get total-revenue) }
)