Source Code

;; Prediction Market Contract
;; Bet on future outcomes

(define-constant err-market-closed (err u100))
(define-constant err-market-not-resolved (err u101))
(define-constant err-not-authorized (err u102))
(define-constant err-already-claimed (err u103))

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

(define-map markets
    uint
    {
        creator: principal,
        question: (string-utf8 500),
        end-block: uint,
        total-yes: uint,
        total-no: uint,
        resolved: bool,
        outcome: (optional bool)
    }
)

(define-map positions
    {market-id: uint, user: principal}
    {
        yes-amount: uint,
        no-amount: uint,
        claimed: bool
    }
)

(define-public (create-market (question (string-utf8 500)) (duration uint))
    (let ((market-id (var-get market-nonce)))
        (map-set markets market-id {
            creator: tx-sender,
            question: question,
            end-block: (+ block-height duration),
            total-yes: u0,
            total-no: u0,
            resolved: false,
            outcome: none
        })
        (var-set market-nonce (+ market-id u1))
        (ok market-id)
    )
)

(define-public (bet (market-id uint) (bet-yes bool) (amount uint))
    (let
        (
            (market (unwrap! (map-get? markets market-id) err-market-closed))
            (position-key {market-id: market-id, user: tx-sender})
            (current-position (default-to {yes-amount: u0, no-amount: u0, claimed: false} 
                              (map-get? positions position-key)))
        )
        (asserts! (< block-height (get end-block market)) err-market-closed)
        (asserts! (not (get resolved market)) err-market-closed)
        
        (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
        
        (if bet-yes
            (begin
                (map-set markets market-id (merge market {
                    total-yes: (+ (get total-yes market) amount)
                }))
                (map-set positions position-key (merge current-position {
                    yes-amount: (+ (get yes-amount current-position) amount)
                }))
            )
            (begin
                (map-set markets market-id (merge market {
                    total-no: (+ (get total-no market) amount)
                }))
                (map-set positions position-key (merge current-position {
                    no-amount: (+ (get no-amount current-position) amount)
                }))
            )
        )
        (ok true)
    )
)

(define-public (resolve-market (market-id uint) (outcome bool))
    (let ((market (unwrap! (map-get? markets market-id) err-market-closed)))
        (asserts! (is-eq tx-sender (get creator market)) err-not-authorized)
        (asserts! (>= block-height (get end-block market)) err-market-closed)
        (asserts! (not (get resolved market)) err-market-closed)
        
        (map-set markets market-id (merge market {
            resolved: true,
            outcome: (some outcome)
        }))
        (ok true)
    )
)

(define-public (claim-winnings (market-id uint))
    (let
        (
            (market (unwrap! (map-get? markets market-id) err-market-closed))
            (position-key {market-id: market-id, user: tx-sender})
            (position (unwrap! (map-get? positions position-key) err-not-authorized))
            (outcome (unwrap! (get outcome market) err-market-not-resolved))
        )
        (asserts! (get resolved market) err-market-not-resolved)
        (asserts! (not (get claimed position)) err-already-claimed)
        
        (let
            (
                (winning-amount (if outcome (get yes-amount position) (get no-amount position)))
                (total-pool (+ (get total-yes market) (get total-no market)))
                (winning-pool (if outcome (get total-yes market) (get total-no market)))
                (payout (if (> winning-pool u0)
                           (/ (* winning-amount total-pool) winning-pool)
                           u0))
            )
            (if (> payout u0)
                (try! (as-contract (stx-transfer? payout tx-sender tx-sender)))
                true
            )
            (map-set positions position-key (merge position {claimed: true}))
            (ok payout)
        )
    )
)

(define-read-only (get-market (market-id uint))
    (map-get? markets market-id)
)

(define-read-only (get-position (market-id uint) (user principal))
    (map-get? positions {market-id: market-id, user: user})
)

Functions (6)

FunctionAccessArgs
create-marketpublicquestion: (string-utf8 500
betpublicmarket-id: uint, bet-yes: bool, amount: uint
resolve-marketpublicmarket-id: uint, outcome: bool
claim-winningspublicmarket-id: uint
get-marketread-onlymarket-id: uint
get-positionread-onlymarket-id: uint, user: principal