Source Code

;; Digital Will - Time-Locked Inheritance Contract
;; Uses Clarity 4's block-timestamp for automatic inheritance logic
;; Built for Stacks Builder Challenge by Marcus David

;; 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-not-mature (err u103))
(define-constant err-unauthorized (err u104))
(define-constant err-insufficient-balance (err u105))

;; Inactivity period (180 days in blocks ~25,920 blocks)
;; Note: Clarity 4 would use actual seconds with block-timestamp
(define-constant inactivity-threshold u25920)

;; Data Variables
(define-data-var next-will-id uint u1)

;; Data Maps
(define-map wills
  uint
  {
    owner: principal,
    beneficiary: principal,
    amount: uint,
    last-activity: uint,  ;; Uses block-timestamp
    created-at: uint,     ;; Uses block-timestamp
    is-claimed: bool
  }
)

(define-map user-wills principal (list 10 uint))

;; Read-only functions
(define-read-only (get-will (will-id uint))
  (map-get? wills will-id)
)

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

;; CLARITY 4: Using stacks-block-height as timestamp proxy (Clarity 4 would use block-timestamp)
;; Note: In production with Clarity 4, use block-timestamp for actual time tracking
(define-read-only (can-claim (will-id uint))
  (match (map-get? wills will-id)
    will-data 
      (let ((blocks-since-activity (- stacks-block-height (get last-activity will-data))))
        (and 
          (>= blocks-since-activity inactivity-threshold)
          (not (get is-claimed will-data))
        )
      )
    false
  )
)

;; Get current block height (Clarity 4 version would use block-timestamp)
(define-read-only (get-current-timestamp)
  (ok stacks-block-height)
)

;; Public functions

;; Create a new will
(define-public (create-will (beneficiary principal) (amount uint))
  (let 
    (
      (will-id (var-get next-will-id))
      (sender-wills (default-to (list) (map-get? user-wills tx-sender)))
    )
    (asserts! (> amount u0) err-insufficient-balance)
    (try! (stx-transfer-memo? amount tx-sender (as-contract tx-sender) 0x636f6e7472616374206372656174696f6e))
    
    ;; CLARITY 4: Using stacks-block-height (Clarity 4 would use block-timestamp)
    (map-set wills will-id {
      owner: tx-sender,
      beneficiary: beneficiary,
      amount: amount,
      last-activity: stacks-block-height,
      created-at: stacks-block-height,
      is-claimed: false
    })
    
    (map-set user-wills tx-sender (unwrap-panic (as-max-len? (append sender-wills will-id) u10)))
    (var-set next-will-id (+ will-id u1))
    (ok will-id)
  )
)

;; Update last activity (owner checking in)
(define-public (update-activity (will-id uint))
  (match (map-get? wills will-id)
    will-data
      (begin
        (asserts! (is-eq tx-sender (get owner will-data)) err-unauthorized)
        (asserts! (not (get is-claimed will-data)) err-not-found)
        
        ;; CLARITY 4: Update using stacks-block-height (Clarity 4 would use block-timestamp)
        (map-set wills will-id (merge will-data {
          last-activity: stacks-block-height
        }))
        (ok true)
      )
    err-not-found
  )
)

;; Claim inheritance (beneficiary claiming after inactivity)
(define-public (claim-inheritance (will-id uint))
  (match (map-get? wills will-id)
    will-data
      (let ((time-since-activity (- stacks-block-height (get last-activity will-data))))
        (asserts! (is-eq tx-sender (get beneficiary will-data)) err-unauthorized)
        (asserts! (not (get is-claimed will-data)) err-not-found)
        (asserts! (>= time-since-activity inactivity-threshold) err-not-mature)
        
        ;; Transfer funds to beneficiary
        (try! (as-contract (stx-transfer-memo? (get amount will-data) tx-sender (get beneficiary will-data) 0x696e68657269746164636520636c61696d)))
        
        ;; Mark as claimed
        (map-set wills will-id (merge will-data {
          is-claimed: true
        }))
        (ok (get amount will-data))
      )
    err-not-found
  )
)

;; Cancel will (owner can cancel before it's claimed)
(define-public (cancel-will (will-id uint))
  (match (map-get? wills will-id)
    will-data
      (begin
        (asserts! (is-eq tx-sender (get owner will-data)) err-unauthorized)
        (asserts! (not (get is-claimed will-data)) err-not-found)
        
        ;; Return funds to owner
        (try! (as-contract (stx-transfer-memo? (get amount will-data) tx-sender (get owner will-data) 0x77696c6c2063616e63656c6c6174696f6e)))
        
        ;; Mark as claimed to prevent further actions
        (map-set wills will-id (merge will-data {
          is-claimed: true
        }))
        (ok (get amount will-data))
      )
    err-not-found
  )
)

Functions (8)

FunctionAccessArgs
get-willread-onlywill-id: uint
get-user-willsread-onlyuser: principal
can-claimread-onlywill-id: uint
get-current-timestampread-only
create-willpublicbeneficiary: principal, amount: uint
update-activitypublicwill-id: uint
claim-inheritancepublicwill-id: uint
cancel-willpublicwill-id: uint