Source Code

;; Decentralized Escrow System
;; Secure P2P transactions with automated release conditions

(define-constant contract-owner tx-sender)
(define-constant err-not-authorized (err u100))
(define-constant err-escrow-not-found (err u101))
(define-constant err-already-released (err u102))
(define-constant err-not-expired (err u103))
(define-constant err-invalid-amount (err u104))

(define-map escrows
    { escrow-id: uint }
    {
        seller: principal,
        buyer: principal,
        amount: uint,
        released: bool,
        created-at: uint,
        expiry: uint
    }
)

(define-data-var escrow-counter uint u0)

;; Create new escrow
(define-public (create-escrow (seller principal) (amount uint) (duration uint))
    (let
        (
            (escrow-id (+ (var-get escrow-counter) u1))
            (current-block stacks-block-height)
        )
        (asserts! (> amount u0) err-invalid-amount)
        (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
        (map-set escrows
            { escrow-id: escrow-id }
            {
                seller: seller,
                buyer: tx-sender,
                amount: amount,
                released: false,
                created-at: current-block,
                expiry: (+ current-block duration)
            }
        )
        (var-set escrow-counter escrow-id)
        (ok escrow-id)
    )
)

;; Release escrow to seller
(define-public (release-escrow (escrow-id uint))
    (let
        (
            (escrow (unwrap! (map-get? escrows { escrow-id: escrow-id }) err-escrow-not-found))
        )
        (asserts! (is-eq tx-sender (get buyer escrow)) err-not-authorized)
        (asserts! (not (get released escrow)) err-already-released)
        (try! (as-contract (stx-transfer? (get amount escrow) tx-sender (get seller escrow))))
        (map-set escrows
            { escrow-id: escrow-id }
            (merge escrow { released: true })
        )
        (ok true)
    )
)

;; Refund if expired
(define-public (refund-escrow (escrow-id uint))
    (let
        (
            (escrow (unwrap! (map-get? escrows { escrow-id: escrow-id }) err-escrow-not-found))
        )
        (asserts! (>= stacks-block-height (get expiry escrow)) err-not-expired)
        (asserts! (not (get released escrow)) err-already-released)
        (try! (as-contract (stx-transfer? (get amount escrow) tx-sender (get buyer escrow))))
        (map-set escrows
            { escrow-id: escrow-id }
            (merge escrow { released: true })
        )
        (ok true)
    )
)

;; Read-only functions
(define-read-only (get-escrow (escrow-id uint))
    (map-get? escrows { escrow-id: escrow-id })
)

Functions (4)

FunctionAccessArgs
create-escrowpublicseller: principal, amount: uint, duration: uint
release-escrowpublicescrow-id: uint
refund-escrowpublicescrow-id: uint
get-escrowread-onlyescrow-id: uint