Source Code

(define-constant ERR_NOT_AUTHORIZED (err u100))
(define-constant ERR_PROXY_NOT_FOUND (err u101))
(define-constant ERR_INVALID_IMPLEMENTATION (err u102))
(define-constant ERR_METADATA_TOO_LARGE (err u103))
(define-constant ERR_ALREADY_INITIALIZED (err u104))
(define-constant ERR_INVALID_SIGNATURE (err u105))
(define-constant ERR_EXPIRED (err u106))
(define-constant ERR_INVALID_HASH (err u107))

(define-constant MAX_METADATA_SIZE u1024)

(define-data-var contract-owner principal tx-sender)
(define-data-var proxy-nonce uint u0)

(define-map proxies
  uint
  {
    implementation: principal,
    metadata: (buff 1024),
    metadata-length: uint,
    creator: principal,
    created-at: uint,
    initialized: bool
  }
)

(define-map proxy-by-creator
  principal
  (list 50 uint)
)

(define-map authorized-deployers principal bool)

(define-read-only (get-owner)
  (var-get contract-owner)
)

(define-read-only (get-proxy (proxy-id uint))
  (map-get? proxies proxy-id)
)

(define-read-only (get-proxy-count)
  (var-get proxy-nonce)
)

(define-read-only (get-implementation (proxy-id uint))
  (match (map-get? proxies proxy-id)
    proxy (some (get implementation proxy))
    none
  )
)

(define-read-only (get-metadata (proxy-id uint))
  (match (map-get? proxies proxy-id)
    proxy (some (get metadata proxy))
    none
  )
)

(define-read-only (get-metadata-length (proxy-id uint))
  (match (map-get? proxies proxy-id)
    proxy (some (get metadata-length proxy))
    none
  )
)

(define-read-only (is-initialized (proxy-id uint))
  (match (map-get? proxies proxy-id)
    proxy (get initialized proxy)
    false
  )
)

(define-read-only (get-proxies-by-creator (creator principal))
  (default-to (list) (map-get? proxy-by-creator creator))
)

(define-read-only (is-authorized-deployer (deployer principal))
  (default-to false (map-get? authorized-deployers deployer))
)

(define-read-only (verify-implementation-hash (impl principal) (expected-hash (buff 32)))
  (match (contract-hash? impl)
    hash (is-eq hash expected-hash)
    err-val false
  )
)

(define-read-only (get-current-time)
  stacks-block-time
)

(define-read-only (verify-p256-signature (msg-hash (buff 32)) (sig (buff 64)) (pubkey (buff 33)))
  (secp256r1-verify msg-hash sig pubkey)
)

(define-read-only (metadata-to-ascii (data (buff 128)))
  (to-ascii? data)
)

(define-read-only (encode-proxy-data (proxy-id uint) (impl principal) (metadata (buff 128)))
  {
    proxy-id: proxy-id,
    implementation: impl,
    metadata-ascii: (to-ascii? metadata),
    created-at: stacks-block-time
  }
)

(define-public (create-proxy (implementation principal) (metadata (buff 1024)))
  (let
    (
      (new-id (+ (var-get proxy-nonce) u1))
      (metadata-len (len metadata))
      (creator-proxies (default-to (list) (map-get? proxy-by-creator tx-sender)))
    )
    (asserts! (<= metadata-len MAX_METADATA_SIZE) ERR_METADATA_TOO_LARGE)
    (asserts! (is-ok (contract-hash? implementation)) ERR_INVALID_IMPLEMENTATION)
    (map-set proxies new-id
      {
        implementation: implementation,
        metadata: metadata,
        metadata-length: metadata-len,
        creator: tx-sender,
        created-at: stacks-block-time,
        initialized: false
      }
    )
    (map-set proxy-by-creator tx-sender
      (unwrap-panic (as-max-len? (append creator-proxies new-id) u50))
    )
    (var-set proxy-nonce new-id)
    (ok new-id)
  )
)

(define-public (create-proxy-verified
    (implementation principal)
    (metadata (buff 1024))
    (expected-hash (buff 32))
    (msg-hash (buff 32))
    (sig (buff 64))
    (pubkey (buff 33))
    (deadline uint)
  )
  (let
    (
      (new-id (+ (var-get proxy-nonce) u1))
      (metadata-len (len metadata))
      (creator-proxies (default-to (list) (map-get? proxy-by-creator tx-sender)))
    )
    (asserts! (<= metadata-len MAX_METADATA_SIZE) ERR_METADATA_TOO_LARGE)
    (asserts! (>= deadline stacks-block-time) ERR_EXPIRED)
    (asserts! (secp256r1-verify msg-hash sig pubkey) ERR_INVALID_SIGNATURE)
    (asserts! (verify-implementation-hash implementation expected-hash) ERR_INVALID_HASH)
    (map-set proxies new-id
      {
        implementation: implementation,
        metadata: metadata,
        metadata-length: metadata-len,
        creator: tx-sender,
        created-at: stacks-block-time,
        initialized: false
      }
    )
    (map-set proxy-by-creator tx-sender
      (unwrap-panic (as-max-len? (append creator-proxies new-id) u50))
    )
    (var-set proxy-nonce new-id)
    (ok new-id)
  )
)

(define-public (initialize-proxy (proxy-id uint))
  (let
    (
      (proxy (unwrap! (map-get? proxies proxy-id) ERR_PROXY_NOT_FOUND))
    )
    (asserts! (is-eq tx-sender (get creator proxy)) ERR_NOT_AUTHORIZED)
    (asserts! (not (get initialized proxy)) ERR_ALREADY_INITIALIZED)
    (map-set proxies proxy-id
      (merge proxy { initialized: true })
    )
    (ok true)
  )
)

(define-public (update-implementation (proxy-id uint) (new-implementation principal))
  (let
    (
      (proxy (unwrap! (map-get? proxies proxy-id) ERR_PROXY_NOT_FOUND))
    )
    (asserts! (is-eq tx-sender (get creator proxy)) ERR_NOT_AUTHORIZED)
    (asserts! (not (get initialized proxy)) ERR_ALREADY_INITIALIZED)
    (asserts! (is-ok (contract-hash? new-implementation)) ERR_INVALID_IMPLEMENTATION)
    (map-set proxies proxy-id
      (merge proxy { implementation: new-implementation })
    )
    (ok true)
  )
)

(define-public (set-authorized-deployer (deployer principal) (authorized bool))
  (begin
    (asserts! (is-eq tx-sender (var-get contract-owner)) ERR_NOT_AUTHORIZED)
    (map-set authorized-deployers deployer authorized)
    (ok true)
  )
)

(define-public (transfer-ownership (new-owner principal))
  (begin
    (asserts! (is-eq tx-sender (var-get contract-owner)) ERR_NOT_AUTHORIZED)
    (var-set contract-owner new-owner)
    (ok true)
  )
)

Functions (20)

FunctionAccessArgs
get-ownerread-only
get-proxyread-onlyproxy-id: uint
get-proxy-countread-only
get-implementationread-onlyproxy-id: uint
get-metadataread-onlyproxy-id: uint
get-metadata-lengthread-onlyproxy-id: uint
is-initializedread-onlyproxy-id: uint
get-proxies-by-creatorread-onlycreator: principal
is-authorized-deployerread-onlydeployer: principal
verify-implementation-hashread-onlyimpl: principal, expected-hash: (buff 32
get-current-timeread-only
verify-p256-signatureread-onlymsg-hash: (buff 32
metadata-to-asciiread-onlydata: (buff 128
encode-proxy-dataread-onlyproxy-id: uint, impl: principal, metadata: (buff 128
create-proxypublicimplementation: principal, metadata: (buff 1024
create-proxy-verifiedpublicimplementation: principal, metadata: (buff 1024
initialize-proxypublicproxy-id: uint
update-implementationpublicproxy-id: uint, new-implementation: principal
set-authorized-deployerpublicdeployer: principal, authorized: bool
transfer-ownershippublicnew-owner: principal