Source Code

;; Time-Locked Vault Contract
;; Lock STX until a specific block height

(define-constant err-not-owner (err u100))
(define-constant err-still-locked (err u101))
(define-constant err-vault-not-found (err u102))
(define-constant err-already-withdrawn (err u103))

(define-data-var vault-nonce uint u0)

(define-map vaults
    uint
    {
        owner: principal,
        amount: uint,
        unlock-block: uint,
        withdrawn: bool
    }
)

;; Create a time-locked vault
(define-public (create-vault (amount uint) (lock-duration uint))
    (let
        (
            (vault-id (var-get vault-nonce))
            (unlock-block (+ block-height lock-duration))
        )
        (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
        
        (map-set vaults vault-id {
            owner: tx-sender,
            amount: amount,
            unlock-block: unlock-block,
            withdrawn: false
        })
        
        (var-set vault-nonce (+ vault-id u1))
        (print {event: "vault-created", vault-id: vault-id, amount: amount, unlock-block: unlock-block})
        (ok vault-id)
    )
)

;; Withdraw from vault after unlock time
(define-public (withdraw (vault-id uint))
    (let
        (
            (vault (unwrap! (map-get? vaults vault-id) err-vault-not-found))
        )
        (asserts! (is-eq tx-sender (get owner vault)) err-not-owner)
        (asserts! (>= block-height (get unlock-block vault)) err-still-locked)
        (asserts! (not (get withdrawn vault)) err-already-withdrawn)
        
        (try! (as-contract (stx-transfer? (get amount vault) tx-sender (get owner vault))))
        
        (map-set vaults vault-id (merge vault {withdrawn: true}))
        (print {event: "vault-withdrawn", vault-id: vault-id, amount: (get amount vault)})
        (ok true)
    )
)

;; Extend lock period (owner only)
(define-public (extend-lock (vault-id uint) (additional-blocks uint))
    (let
        (
            (vault (unwrap! (map-get? vaults vault-id) err-vault-not-found))
        )
        (asserts! (is-eq tx-sender (get owner vault)) err-not-owner)
        (asserts! (not (get withdrawn vault)) err-already-withdrawn)
        
        (map-set vaults vault-id (merge vault {
            unlock-block: (+ (get unlock-block vault) additional-blocks)
        }))
        (ok true)
    )
)

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

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

(define-read-only (is-unlocked (vault-id uint))
    (match (map-get? vaults vault-id)
        vault
        (>= block-height (get unlock-block vault))
        false
    )
)

(define-read-only (blocks-until-unlock (vault-id uint))
    (match (map-get? vaults vault-id)
        vault
        (if (>= block-height (get unlock-block vault))
            u0
            (- (get unlock-block vault) block-height))
        u0
    )
)

Functions (7)

FunctionAccessArgs
create-vaultpublicamount: uint, lock-duration: uint
withdrawpublicvault-id: uint
extend-lockpublicvault-id: uint, additional-blocks: uint
get-vaultread-onlyvault-id: uint
get-vault-countread-only
is-unlockedread-onlyvault-id: uint
blocks-until-unlockread-onlyvault-id: uint