Source Code

;; Timelock Contract
(define-constant contract-owner tx-sender)
(define-constant err-unauthorized (err u401))
(define-constant err-not-ready (err u402))
(define-constant err-already-executed (err u403))
(define-constant err-invalid-delay (err u404))

;; Timelock state
(define-data-var min-delay uint u1440) ;; 1 day in blocks
(define-data-var max-delay uint u43200) ;; 30 days in blocks
(define-data-var transaction-counter uint u0)

;; Queued transactions
(define-map queued-transactions uint {
  target: principal,
  function-name: (string-ascii 50),
  args: (list 10 (buff 34)),
  eta: uint,
  executed: bool,
  cancelled: bool
})

;; Queue transaction
(define-public (queue-transaction (target principal) (function-name (string-ascii 50)) (args (list 10 (buff 34))) (delay uint))
  (let ((tx-id (+ (var-get transaction-counter) u1))
        (eta (+ block-height delay)))
    (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
    (asserts! (and (>= delay (var-get min-delay)) (<= delay (var-get max-delay))) err-invalid-delay)
    
    (var-set transaction-counter tx-id)
    (map-set queued-transactions tx-id {
      target: target,
      function-name: function-name,
      args: args,
      eta: eta,
      executed: false,
      cancelled: false
    })
    (ok tx-id)))

;; Execute transaction
(define-public (execute-transaction (tx-id uint))
  (let ((tx-data (unwrap! (map-get? queued-transactions tx-id) (err u404))))
    (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
    (asserts! (>= block-height (get eta tx-data)) err-not-ready)
    (asserts! (not (get executed tx-data)) err-already-executed)
    (asserts! (not (get cancelled tx-data)) (err u405))
    
    (map-set queued-transactions tx-id (merge tx-data {executed: true}))
    (ok true)))

;; Cancel transaction
(define-public (cancel-transaction (tx-id uint))
  (let ((tx-data (unwrap! (map-get? queued-transactions tx-id) (err u404))))
    (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
    (asserts! (not (get executed tx-data)) err-already-executed)
    
    (map-set queued-transactions tx-id (merge tx-data {cancelled: true}))
    (ok true)))

;; Set delays
(define-public (set-min-delay (delay uint))
  (begin
    (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
    (var-set min-delay delay)
    (ok true)))

(define-public (set-max-delay (delay uint))
  (begin
    (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
    (var-set max-delay delay)
    (ok true)))

;; Read functions
(define-read-only (get-transaction (tx-id uint))
  (map-get? queued-transactions tx-id))

(define-read-only (is-ready (tx-id uint))
  (match (map-get? queued-transactions tx-id)
    tx-data (and (>= block-height (get eta tx-data)) (not (get executed tx-data)) (not (get cancelled tx-data)))
    false))

(define-read-only (get-delays)
  {min-delay: (var-get min-delay), max-delay: (var-get max-delay)})

(define-read-only (get-eta (tx-id uint))
  (match (map-get? queued-transactions tx-id)
    tx-data (some (get eta tx-data))
    none))

Functions (9)

FunctionAccessArgs
queue-transactionpublictarget: principal, function-name: (string-ascii 50
execute-transactionpublictx-id: uint
cancel-transactionpublictx-id: uint
set-min-delaypublicdelay: uint
set-max-delaypublicdelay: uint
get-transactionread-onlytx-id: uint
is-readyread-onlytx-id: uint
get-delaysread-only
get-etaread-onlytx-id: uint