Source Code

;; Proposal Execution - Treasury Management (Clarity 4)
;; This contract executes approved proposals and manages the treasury

;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant EXECUTION-DELAY u86400)          ;; Clarity 4: 24 hours in seconds

;; Error codes
(define-constant ERR-NOT-AUTHORIZED (err u301))
(define-constant ERR-PROPOSAL-NOT-FOUND (err u302))
(define-constant ERR-PROPOSAL-NOT-PASSED (err u303))
(define-constant ERR-ALREADY-EXECUTED (err u304))
(define-constant ERR-EXECUTION-DELAY-NOT-MET (err u305))
(define-constant ERR-INSUFFICIENT-TREASURY (err u306))
(define-constant ERR-INVALID-AMOUNT (err u307))
(define-constant ERR-TRANSFER-FAILED (err u308))

;; Data variables
(define-data-var treasury-balance uint u0)
(define-data-var total-executed uint u0)

;; Data maps

;; Execution queue with Clarity 4 timestamps
(define-map execution-queue
    { proposal-id: uint }
    {
        queued-at: uint,                     ;; Clarity 4: Unix timestamp
        ready-at: uint,                      ;; Clarity 4: Unix timestamp
        executed-at: (optional uint),        ;; Clarity 4: Unix timestamp
        executor: (optional principal),
        action-type: (string-ascii 50),
        recipient: (optional principal),
        amount: uint,
        executed: bool
    }
)

;; Treasury transactions with Clarity 4 timestamps
(define-map treasury-transactions
    { tx-id: uint }
    {
        proposal-id: uint,
        amount: uint,
        recipient: principal,
        timestamp: uint,                     ;; Clarity 4: Unix timestamp
        tx-type: (string-ascii 20)
    }
)

(define-data-var next-tx-id uint u0)

;; Read-only functions

;; Get treasury balance
(define-read-only (get-treasury-balance)
    (ok (var-get treasury-balance))
)

;; Get total executed proposals
(define-read-only (get-total-executed)
    (ok (var-get total-executed))
)

;; Get execution details
(define-read-only (get-execution-details (proposal-id uint))
    (ok (map-get? execution-queue { proposal-id: proposal-id }))
)

;; Check if proposal is ready for execution
(define-read-only (is-ready-for-execution (proposal-id uint))
    (match (map-get? execution-queue { proposal-id: proposal-id })
        execution
            (ok (and
                (>= stacks-block-time (get ready-at execution))
                (not (get executed execution))
            ))
        (ok false)
    )
)

;; Get treasury transaction
(define-read-only (get-treasury-transaction (tx-id uint))
    (ok (map-get? treasury-transactions { tx-id: tx-id }))
)

;; Public functions

;; Queue proposal for execution (only contract owner or authorized)
(define-public (queue-proposal (proposal-id uint) (action-type (string-ascii 50)) (recipient (optional principal)) (amount uint))
    (begin
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        (asserts! (is-none (map-get? execution-queue { proposal-id: proposal-id })) ERR-ALREADY-EXECUTED)

        (let
            (
                (queued-time stacks-block-time)
                (ready-time (+ stacks-block-time EXECUTION-DELAY))
            )
            (map-set execution-queue
                { proposal-id: proposal-id }
                {
                    queued-at: queued-time,                  ;; Clarity 4: Unix timestamp
                    ready-at: ready-time,                    ;; Clarity 4: Unix timestamp
                    executed-at: none,
                    executor: none,
                    action-type: action-type,
                    recipient: recipient,
                    amount: amount,
                    executed: false
                }
            )
            (print {
                event: "proposal-queued",
                proposal-id: proposal-id,
                queued-at: queued-time,
                ready-at: ready-time
            })
            (ok true)
        )
    )
)

;; Execute queued proposal
(define-public (execute-proposal (proposal-id uint))
    (let
        (
            (execution (unwrap! (map-get? execution-queue { proposal-id: proposal-id }) ERR-PROPOSAL-NOT-FOUND))
        )
        (asserts! (not (get executed execution)) ERR-ALREADY-EXECUTED)
        (asserts! (>= stacks-block-time (get ready-at execution)) ERR-EXECUTION-DELAY-NOT-MET)

        ;; Check if it's a treasury transfer and execute if needed
        (try! (if (is-eq (get action-type execution) "transfer")
            (execute-treasury-transfer proposal-id execution)
            (ok true)
        ))

        ;; Mark as executed
        (map-set execution-queue
            { proposal-id: proposal-id }
            (merge execution {
                executed: true,
                executed-at: (some stacks-block-time),       ;; Clarity 4: Unix timestamp
                executor: (some tx-sender)
            })
        )

        (var-set total-executed (+ (var-get total-executed) u1))

        (print {
            event: "proposal-executed",
            proposal-id: proposal-id,
            executor: tx-sender,
            timestamp: stacks-block-time
        })
        (ok true)
    )
)

;; Execute treasury transfer (private helper)
(define-private (execute-treasury-transfer (proposal-id uint) (execution { queued-at: uint, ready-at: uint, executed-at: (optional uint), executor: (optional principal), action-type: (string-ascii 50), recipient: (optional principal), amount: uint, executed: bool }))
    (let
        (
            (amount (get amount execution))
            (recipient (unwrap! (get recipient execution) ERR-INVALID-AMOUNT))
        )
        (asserts! (>= (var-get treasury-balance) amount) ERR-INSUFFICIENT-TREASURY)

        ;; Deduct from treasury
        (var-set treasury-balance (- (var-get treasury-balance) amount))

        ;; Record transaction
        (let
            (
                (tx-id (var-get next-tx-id))
            )
            (var-set next-tx-id (+ tx-id u1))

            (map-set treasury-transactions
                { tx-id: tx-id }
                {
                    proposal-id: proposal-id,
                    amount: amount,
                    recipient: recipient,
                    timestamp: stacks-block-time,            ;; Clarity 4: Unix timestamp
                    tx-type: "withdrawal"
                }
            )

            (print {
                event: "treasury-transfer",
                tx-id: tx-id,
                proposal-id: proposal-id,
                amount: amount,
                recipient: recipient,
                timestamp: stacks-block-time
            })
            (ok true)
        )
    )
)

;; Deposit to treasury
(define-public (deposit-to-treasury (amount uint))
    (begin
        (asserts! (> amount u0) ERR-INVALID-AMOUNT)

        ;; Track deposit (actual STX transfer would be handled off-chain or separately)
        (var-set treasury-balance (+ (var-get treasury-balance) amount))

        (let
            (
                (tx-id (var-get next-tx-id))
            )
            (var-set next-tx-id (+ tx-id u1))

            (map-set treasury-transactions
                { tx-id: tx-id }
                {
                    proposal-id: u0,
                    amount: amount,
                    recipient: tx-sender,
                    timestamp: stacks-block-time,            ;; Clarity 4: Unix timestamp
                    tx-type: "deposit"
                }
            )

            (print {
                event: "treasury-deposit",
                tx-id: tx-id,
                amount: amount,
                depositor: tx-sender,
                timestamp: stacks-block-time
            })
            (ok true)
        )
    )
)

;; Cancel queued proposal (only contract owner)
(define-public (cancel-execution (proposal-id uint))
    (let
        (
            (execution (unwrap! (map-get? execution-queue { proposal-id: proposal-id }) ERR-PROPOSAL-NOT-FOUND))
        )
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        (asserts! (not (get executed execution)) ERR-ALREADY-EXECUTED)

        (map-delete execution-queue { proposal-id: proposal-id })

        (print {
            event: "execution-cancelled",
            proposal-id: proposal-id,
            cancelled-by: tx-sender,
            timestamp: stacks-block-time
        })
        (ok true)
    )
)

Functions (9)

FunctionAccessArgs
get-treasury-balanceread-only
get-total-executedread-only
get-execution-detailsread-onlyproposal-id: uint
is-ready-for-executionread-onlyproposal-id: uint
get-treasury-transactionread-onlytx-id: uint
queue-proposalpublicproposal-id: uint, action-type: (string-ascii 50
execute-proposalpublicproposal-id: uint
deposit-to-treasurypublicamount: uint
cancel-executionpublicproposal-id: uint