Source Code

(define-constant CANT_DO_THAT (err u600))
(define-constant NOT_AUTHORIZED (err u500))

(define-constant CONTRACT-OWNER tx-sender)

(define-non-fungible-token STEAL-ME uint)

(define-data-var json-uri (string-ascii 100) "https://forceprime.io/hackathon/nft2.json")
(define-data-var token-counter uint u0)

(define-data-var steal-count uint u0)
(define-data-var steal-cost uint u0)
(define-data-var last-block uint u0)
(define-data-var first-block uint u0)
(define-data-var winner principal CONTRACT-OWNER)
(define-data-var winner-blocks uint u0)
(define-data-var steal-block uint u0)

(define-map player2count
    principal
    uint
)

(define-read-only (get-owner (token-id uint))
	(ok (nft-get-owner? STEAL-ME token-id))
)

(define-read-only (get-token-uri (token-id uint))
    (ok (var-get json-uri))
)

(define-read-only (get-prize)
    (ok (stx-get-balance (as-contract tx-sender)))
)

(define-read-only (get-steal-attempts)
    (ok (var-get steal-count))
)

(define-read-only (get-blocks-left)
    (ok (- (var-get last-block) block-height))
)

(define-public (finalize)
    (let
        (
            (currentOwner (unwrap-panic (nft-get-owner? STEAL-ME u1)))
            (currentBalance (stx-get-balance (as-contract tx-sender)))
        )
        
        (asserts! (> block-height (var-get last-block)) CANT_DO_THAT)
        (asserts! (> currentBalance u0) CANT_DO_THAT)

        (update-blocks-for currentOwner)
        (update-current-winner currentOwner)
        (try! (as-contract (stx-transfer? currentBalance tx-sender (var-get winner))))
        (if (is-eq currentOwner (var-get winner)) true
            (try! (nft-transfer? STEAL-ME u1 currentOwner (var-get winner))))
        
        (ok true)
    )
)

(define-public (steal)
    (let 
        (
            (cost (var-get steal-cost))
            (currentOwner (unwrap-panic (nft-get-owner? STEAL-ME u1)))
            (stealRoll (roll-steal))
        )
        (asserts! (is-eq (var-get token-counter) u1) CANT_DO_THAT)
        (asserts! (>= (stx-get-balance tx-sender) cost) CANT_DO_THAT)
        (asserts! (<= block-height (var-get last-block)) CANT_DO_THAT)
        (asserts! (not (is-eq currentOwner tx-sender)) CANT_DO_THAT)

        (try! (stx-transfer? cost tx-sender (as-contract tx-sender)))
        (var-set steal-count (+ (var-get steal-count) u1))
        (if stealRoll (process-steal) false)
        (ok stealRoll)
    )
)

(define-private (process-steal)
    (let 
        (
            (currentOwner (unwrap-panic (nft-get-owner? STEAL-ME u1)))
        )
        (unwrap-panic (nft-transfer? STEAL-ME u1 currentOwner tx-sender))
        (update-blocks-for currentOwner)
        (update-current-winner currentOwner)
    )
)

(define-private (update-blocks-for (p principal))
    (let 
        (
            (lastBlock (var-get last-block))
            (maxBlock (if (> block-height lastBlock) lastBlock block-height))
            (blockDelta (- maxBlock (var-get steal-block)))
            (currentBlocks (default-to u0 (map-get? player2count p)))
            (newBlocks (+ blockDelta currentBlocks))
        )
        (map-set player2count p newBlocks)
        (var-set steal-block maxBlock)
    )
)

(define-private (update-current-winner (compareWith principal))
     (let 
        (
            (currentBlocks (default-to u0 (map-get? player2count compareWith)))
        )
        (if (> currentBlocks (var-get winner-blocks))
            (begin
                (var-set winner-blocks currentBlocks)
                (var-set winner compareWith)
            )
            false
        )
    )
)

(define-public (transfer (token-id uint) (sender principal) (recipient principal))
    (begin
        (asserts! (is-eq tx-sender sender) NOT_AUTHORIZED)
        (asserts! (> block-height (var-get last-block)) CANT_DO_THAT)
        (nft-transfer? STEAL-ME token-id sender recipient)
    )
)

(define-public (mint (initialBalance uint) (stealCost uint) (blockCount uint))
    (begin
        (asserts! (is-eq tx-sender CONTRACT-OWNER) CANT_DO_THAT)
        (asserts! (is-eq (var-get token-counter) u0) CANT_DO_THAT)
        (asserts! (>= (stx-get-balance tx-sender) initialBalance) CANT_DO_THAT)

        (var-set steal-cost stealCost)
        (var-set token-counter u1)
        (var-set last-block (+ block-height blockCount))
        (var-set first-block block-height)
        (var-set steal-block block-height)

        (try! (stx-transfer? initialBalance tx-sender (as-contract tx-sender)))
        (try! (nft-mint? STEAL-ME u1 tx-sender))

        (ok 1)
    )
)

(define-private (roll-steal)
    (let
        (
            (vrf (unwrap-panic (get-block-info? vrf-seed (- block-height u1))))
            (thenumber (+ (var-get steal-count) block-height))
            (mixedseed (concat vrf (byte-to-buff (mod thenumber u256))))
            (adr (get hash-bytes (unwrap-panic (principal-destruct? tx-sender))))
            (prndbuff (sha512/256 (concat mixedseed adr)))
            (s (mod (fold + (map buff-to-uint-be prndbuff) u0) u777))
            (v (pow (/ (+ (var-get steal-count) (- block-height (var-get first-block))) u17) u2))
            (vf (if (> v u750) u750 v))
        )
        (if (> s vf) true false)
    )
)

(define-private (byte-to-buff (byte uint))
    (unwrap-panic (element-at 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff byte))
)

Functions (14)

FunctionAccessArgs
get-ownerread-onlytoken-id: uint
get-token-uriread-onlytoken-id: uint
get-prizeread-only
get-steal-attemptsread-only
get-blocks-leftread-only
finalizepublic
stealpublic
process-stealprivate
update-blocks-forprivatep: principal
update-current-winnerprivatecompareWith: principal
transferpublictoken-id: uint, sender: principal, recipient: principal
mintpublicinitialBalance: uint, stealCost: uint, blockCount: uint
roll-stealprivate
byte-to-buffprivatebyte: uint