Source Code

;; title: Hexagram Registry
;; version: 3.0
;; summary: A contract to record encrypted I Ching hexagram readings with timestamps
;; description: This contract allows users to submit encrypted hexagrams and record them
;; permanently on the blockchain. Hexagram data is encrypted client-side before submission.

;; constants
(define-constant ERR_INVALID_HEXAGRAM (err u2))
(define-constant ERR_VRF_SEED_NOT_FOUND (err u3))
(define-constant ERR_INTERNAL (err u5))
(define-constant DEPLOYER tx-sender)
(define-constant REGISTRATION_FEE u100000)

;; data vars
(define-data-var next-id uint u1)

;; data maps
(define-map hexagrams
  { id: uint, owner: principal }
  { hexagram: (buff 512), timestamp: uint })

(define-map owner-hexagram-count
  { owner: principal }
  { count: uint })

(define-map owner-hexagram-index
  { owner: principal, index: uint }
  { id: uint })

;; public functions
(define-public (submit-hexagram
  (hexagram (buff 512))
  (timestamp uint)
)
  (let (
    (current-id (var-get next-id))
    (current-count (default-to u0 (get count (map-get? owner-hexagram-count { owner: tx-sender }))))
  )
    (asserts! (> (len hexagram) u0) ERR_INVALID_HEXAGRAM)
    (asserts! (> timestamp u0) ERR_INVALID_HEXAGRAM)
    (try! (stx-transfer? REGISTRATION_FEE tx-sender DEPLOYER))

    (map-set hexagrams
      { id: current-id, owner: tx-sender }
      { hexagram: hexagram, timestamp: timestamp })

    (map-set owner-hexagram-count
      { owner: tx-sender }
      { count: (+ current-count u1) })

    (map-set owner-hexagram-index
      { owner: tx-sender, index: current-count }
      { id: current-id })

    (var-set next-id (+ current-id u1))
    (ok current-id)
  )
)

(define-read-only (get-hexagram-by-id (id uint))
  (let (
    (hexagram-entry (map-get? hexagrams { id: id, owner: tx-sender }))
  )
    (match hexagram-entry
      entry (ok entry)
      (err u1)
    )
  )
)

;; read only functions
(define-read-only (get-hexagram-by-owner-and-id (owner principal) (id uint))
  (map-get? hexagrams { id: id, owner: owner })
)

(define-read-only (get-current-id)
  (- (var-get next-id) u1)
)

(define-read-only (get-owner-hexagram-count (owner principal))
  (default-to u0 (get count (map-get? owner-hexagram-count { owner: owner })))
)

(define-read-only (get-owner-hexagram-id-at-index (owner principal) (index uint))
  (map-get? owner-hexagram-index { owner: owner, index: index })
)

(define-read-only (get-hexagram-entry (id uint) (owner principal))
  (map-get? hexagrams { id: id, owner: owner })
)

;; private helpers for VRF-based hexagram generation
(define-private (derive-line (seed (buff 32)) (index uint))
  (let (
    (index-buf (unwrap! (to-consensus-buff? index) ERR_INTERNAL))
    (hash (keccak256 (concat seed index-buf)))
    (slice16 (unwrap! (as-max-len? (unwrap! (slice? hash u0 u16) ERR_INTERNAL) u16) ERR_INTERNAL))
    (rand (buff-to-uint-be slice16))
  )
    (ok (+ u6 (mod rand u4)))
  )
)

;; public function: generate a hexagram on-chain using VRF randomness
(define-public (roll-hexagram)
  (let (
    (vrf-seed (unwrap! (get-tenure-info? vrf-seed (- stacks-block-height u1)) ERR_VRF_SEED_NOT_FOUND))
    (personal-seed (keccak256 (concat vrf-seed (unwrap! (to-consensus-buff? tx-sender) ERR_INTERNAL))))
    (line0 (try! (derive-line personal-seed u0)))
    (line1 (try! (derive-line personal-seed u1)))
    (line2 (try! (derive-line personal-seed u2)))
    (line3 (try! (derive-line personal-seed u3)))
    (line4 (try! (derive-line personal-seed u4)))
    (line5 (try! (derive-line personal-seed u5)))
    (lines (list line0 line1 line2 line3 line4 line5))
    (current-id (var-get next-id))
    (current-count (default-to u0 (get count (map-get? owner-hexagram-count { owner: tx-sender }))))
    (hexagram-buf (unwrap! (to-consensus-buff? lines) ERR_INTERNAL))
  )
    (try! (stx-transfer? REGISTRATION_FEE tx-sender DEPLOYER))

    (map-set hexagrams
      { id: current-id, owner: tx-sender }
      { hexagram: hexagram-buf, timestamp: stacks-block-height })

    (map-set owner-hexagram-count
      { owner: tx-sender }
      { count: (+ current-count u1) })

    (map-set owner-hexagram-index
      { owner: tx-sender, index: current-count }
      { id: current-id })

    (var-set next-id (+ current-id u1))
    (ok { id: current-id, lines: lines })
  )
)

Functions (9)

FunctionAccessArgs
submit-hexagrampublichexagram: (buff 512
get-hexagram-by-idread-onlyid: uint
get-hexagram-by-owner-and-idread-onlyowner: principal, id: uint
get-current-idread-only
get-owner-hexagram-countread-onlyowner: principal
get-owner-hexagram-id-at-indexread-onlyowner: principal, index: uint
get-hexagram-entryread-onlyid: uint, owner: principal
derive-lineprivateseed: (buff 32
roll-hexagrampublic