Source Code

;; title: vault-factory
;; version: 1.0.0
;; summary: Vault Factory for deploying multiple vault instances
;; description: Factory contract to create and manage multiple vault instances - Clarity 4

;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-UNAUTHORIZED (err u100))
(define-constant ERR-VAULT-EXISTS (err u101))
(define-constant ERR-VAULT-NOT-FOUND (err u102))
(define-constant ERR-INVALID-FEE (err u103))

;; Data Variables
(define-data-var next-vault-id uint u1)
(define-data-var deployment-fee uint u1000000) ;; 1 STX deployment fee
(define-data-var factory-paused bool false)

;; Data Maps - Using stacks-block-time for Clarity 4
(define-map vaults uint {
  owner: principal,
  vault-contract: principal,
  vault-type: (string-ascii 20),
  created-at: uint,  ;; Clarity 4: Unix timestamp
  is-active: bool,
  total-deposits: uint
})

(define-map user-vaults principal (list 100 uint))

(define-map vault-templates (string-ascii 20) {
  template-name: (string-ascii 50),
  description: (string-ascii 200),
  is-enabled: bool,
  deployment-count: uint
})

;; Initialize vault templates
(map-set vault-templates "standard" {
  template-name: "Standard Vault",
  description: "Basic STX vault with deposit/withdraw functionality",
  is-enabled: true,
  deployment-count: u0
})

(map-set vault-templates "yield" {
  template-name: "Yield Vault",
  description: "Auto-compounding yield optimization vault",
  is-enabled: true,
  deployment-count: u0
})

(map-set vault-templates "insurance" {
  template-name: "Insurance Vault",
  description: "Protected vault with insurance coverage",
  is-enabled: true,
  deployment-count: u0
})

;; Public Functions

;; Create new vault instance
(define-public (create-vault (vault-type (string-ascii 20)))
  (let (
    (vault-id (var-get next-vault-id))
    (template (unwrap! (map-get? vault-templates vault-type) ERR-VAULT-NOT-FOUND))
    (deployer tx-sender)
  )
    (asserts! (not (var-get factory-paused)) ERR-UNAUTHORIZED)
    (asserts! (get is-enabled template) ERR-UNAUTHORIZED)

    ;; Charge deployment fee
    (try! (stx-transfer? (var-get deployment-fee) tx-sender CONTRACT-OWNER))

    ;; Register vault
    (map-set vaults vault-id {
      owner: deployer,
      vault-contract: deployer, ;; In production, this would be the deployed contract principal
      vault-type: vault-type,
      created-at: stacks-block-time,  ;; Clarity 4: Unix timestamp
      is-active: true,
      total-deposits: u0
    })

    ;; Add to user's vault list
    (match (map-get? user-vaults deployer)
      user-vault-list (map-set user-vaults deployer (unwrap-panic (as-max-len? (append user-vault-list vault-id) u100)))
      (map-set user-vaults deployer (list vault-id))
    )

    ;; Update template deployment count
    (map-set vault-templates vault-type
      (merge template { deployment-count: (+ (get deployment-count template) u1) }))

    ;; Increment vault ID
    (var-set next-vault-id (+ vault-id u1))

    ;; Emit event with native print (Clarity 4)
    (print {
      event: "vault-created",
      vault-id: vault-id,
      owner: deployer,
      vault-type: vault-type,
      timestamp: stacks-block-time
    })

    (ok vault-id)
  )
)

;; Deactivate vault
(define-public (deactivate-vault (vault-id uint))
  (let (
    (vault (unwrap! (map-get? vaults vault-id) ERR-VAULT-NOT-FOUND))
  )
    (asserts! (is-eq (get owner vault) tx-sender) ERR-UNAUTHORIZED)
    (asserts! (get is-active vault) ERR-VAULT-NOT-FOUND)

    (map-set vaults vault-id
      (merge vault { is-active: false }))

    (print {
      event: "vault-deactivated",
      vault-id: vault-id,
      owner: tx-sender,
      timestamp: stacks-block-time
    })

    (ok true)
  )
)

;; Update vault deposits (called by vault contracts)
(define-public (update-vault-deposits (vault-id uint) (new-total uint))
  (let (
    (vault (unwrap! (map-get? vaults vault-id) ERR-VAULT-NOT-FOUND))
  )
    ;; In production, verify caller is the vault contract
    (map-set vaults vault-id
      (merge vault { total-deposits: new-total }))
    (ok true)
  )
)

;; Admin Functions

(define-public (set-deployment-fee (new-fee uint))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-UNAUTHORIZED)
    (asserts! (> new-fee u0) ERR-INVALID-FEE)
    (var-set deployment-fee new-fee)
    (ok true)
  )
)

(define-public (pause-factory)
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-UNAUTHORIZED)
    (var-set factory-paused true)
    (ok true)
  )
)

(define-public (resume-factory)
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-UNAUTHORIZED)
    (var-set factory-paused false)
    (ok true)
  )
)

(define-public (add-vault-template
  (template-id (string-ascii 20))
  (name (string-ascii 50))
  (description (string-ascii 200)))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-UNAUTHORIZED)
    (map-set vault-templates template-id {
      template-name: name,
      description: description,
      is-enabled: true,
      deployment-count: u0
    })
    (ok true)
  )
)

(define-public (toggle-template (template-id (string-ascii 20)) (enabled bool))
  (let (
    (template (unwrap! (map-get? vault-templates template-id) ERR-VAULT-NOT-FOUND))
  )
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-UNAUTHORIZED)
    (map-set vault-templates template-id
      (merge template { is-enabled: enabled }))
    (ok true)
  )
)

;; Read-Only Functions

(define-read-only (get-vault (vault-id uint))
  (map-get? vaults vault-id)
)

(define-read-only (get-user-vaults (user principal))
  (default-to (list) (map-get? user-vaults user))
)

(define-read-only (get-vault-template (template-id (string-ascii 20)))
  (map-get? vault-templates template-id)
)

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

(define-read-only (get-next-vault-id)
  (var-get next-vault-id)
)

(define-read-only (is-factory-paused)
  (var-get factory-paused)
)

(define-read-only (get-total-vaults)
  (- (var-get next-vault-id) u1)
)

;; Clarity 4 Enhanced Functions

;; 1. Clarity 4: principal-destruct? - Validate and decompose principal addresses
(define-read-only (validate-vault-owner (owner principal))
  (principal-destruct? owner)
)

;; 2. Clarity 4: int-to-ascii - Format vault ID and fees for display
(define-read-only (format-vault-id (vault-id uint))
  (ok (int-to-ascii vault-id))
)

(define-read-only (format-deployment-fee)
  (ok (int-to-ascii (var-get deployment-fee)))
)

;; 3. Clarity 4: string-to-uint? - Parse string input to vault ID
(define-read-only (parse-vault-id (id-str (string-ascii 20)))
  (match (string-to-uint? id-str)
    parsed-id (ok parsed-id)
    (err u998)
  )
)

;; 4. Clarity 4: buff-to-int-le - Convert buffer to vault identifier
(define-read-only (buffer-to-vault-id (vault-buff (buff 16)))
  (ok (buff-to-uint-le vault-buff))
)

;; Clarity 4: Combine features - Get vault owner info
(define-read-only (get-vault-owner-info (vault-id uint))
  (match (map-get? vaults vault-id)
    vault-data (ok {
      vault-id-str: (int-to-ascii vault-id),
      owner: (get owner vault-data),
      created-timestamp: (get created-at vault-data)
    })
    (err ERR-VAULT-NOT-FOUND)
  )
)

Functions (21)

FunctionAccessArgs
create-vaultpublicvault-type: (string-ascii 20
deactivate-vaultpublicvault-id: uint
update-vault-depositspublicvault-id: uint, new-total: uint
set-deployment-feepublicnew-fee: uint
pause-factorypublic
resume-factorypublic
add-vault-templatepublictemplate-id: (string-ascii 20
toggle-templatepublictemplate-id: (string-ascii 20
get-vaultread-onlyvault-id: uint
get-user-vaultsread-onlyuser: principal
get-vault-templateread-onlytemplate-id: (string-ascii 20
get-deployment-feeread-only
get-next-vault-idread-only
is-factory-pausedread-only
get-total-vaultsread-only
validate-vault-ownerread-onlyowner: principal
format-vault-idread-onlyvault-id: uint
format-deployment-feeread-only
parse-vault-idread-onlyid-str: (string-ascii 20
buffer-to-vault-idread-onlyvault-buff: (buff 16
get-vault-owner-inforead-onlyvault-id: uint