Source Code

;; StakeFlow Staking Contract
;; Stake NFTs to earn STF rewards
;; MAINNET VERSION

;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-NOT-TOKEN-OWNER (err u101))
(define-constant ERR-ALREADY-STAKED (err u102))
(define-constant ERR-NOT-STAKED (err u103))
(define-constant ERR-TRANSFER-FAILED (err u104))

;; Data structures
(define-map staked-nfts
  { token-id: uint }
  {
    owner: principal,
    staked-at: uint,
    last-claim: uint
  }
)

(define-map staker-info
  { staker: principal }
  { staked-count: uint }
)

;; Data vars
(define-data-var total-staked uint u0)
(define-data-var staking-paused bool false)

;; ---------------------------------------------------------
;; Staking Functions
;; ---------------------------------------------------------

(define-public (stake-nft (token-id uint))
  (let
    (
      (nft-owner (unwrap! (contract-call? .stakeflow-nft-mainnet get-owner token-id) ERR-NOT-TOKEN-OWNER))
    )
    ;; Check not paused
    (asserts! (not (var-get staking-paused)) ERR-NOT-AUTHORIZED)
    ;; Verify ownership
    (asserts! (is-eq (some tx-sender) nft-owner) ERR-NOT-TOKEN-OWNER)
    ;; Check not already staked
    (asserts! (is-none (map-get? staked-nfts { token-id: token-id })) ERR-ALREADY-STAKED)
    ;; Transfer NFT to this contract
    (try! (contract-call? .stakeflow-nft-mainnet transfer token-id tx-sender (as-contract tx-sender)))
    ;; Record stake
    (map-set staked-nfts
      { token-id: token-id }
      {
        owner: tx-sender,
        staked-at: block-height,
        last-claim: block-height
      }
    )
    ;; Update staker info
    (map-set staker-info
      { staker: tx-sender }
      { staked-count: (+ (get-staked-count tx-sender) u1) }
    )
    ;; Update total staked
    (var-set total-staked (+ (var-get total-staked) u1))
    (ok true)
  )
)

;; ---------------------------------------------------------
;; Read-only Functions
;; ---------------------------------------------------------

(define-read-only (get-stake-info (token-id uint))
  (map-get? staked-nfts { token-id: token-id })
)

(define-read-only (is-staked (token-id uint))
  (is-some (map-get? staked-nfts { token-id: token-id }))
)

(define-read-only (get-staked-count (staker principal))
  (default-to u0 (get staked-count (map-get? staker-info { staker: staker })))
)

(define-read-only (get-total-staked)
  (var-get total-staked)
)

(define-read-only (get-blocks-staked (token-id uint))
  (match (map-get? staked-nfts { token-id: token-id })
    stake-data (- block-height (get staked-at stake-data))
    u0
  )
)

(define-read-only (get-staker (token-id uint))
  (match (map-get? staked-nfts { token-id: token-id })
    stake-data (some (get owner stake-data))
    none
  )
)

(define-read-only (is-staking-paused)
  (var-get staking-paused)
)

;; ---------------------------------------------------------
;; Internal Functions (Called by other contracts)
;; ---------------------------------------------------------

(define-public (remove-stake (token-id uint))
  (let
    (
      (stake-data (unwrap! (map-get? staked-nfts { token-id: token-id }) ERR-NOT-STAKED))
      (original-owner (get owner stake-data))
    )
    ;; Only unstake contract can call this
    (asserts! (is-eq contract-caller .stakeflow-unstake-mainnet) ERR-NOT-AUTHORIZED)
    ;; Transfer NFT back to owner
    (try! (as-contract (contract-call? .stakeflow-nft-mainnet transfer token-id tx-sender original-owner)))
    ;; Remove stake record
    (map-delete staked-nfts { token-id: token-id })
    ;; Update staker info
    (map-set staker-info
      { staker: original-owner }
      { staked-count: (- (get-staked-count original-owner) u1) }
    )
    ;; Update total staked
    (var-set total-staked (- (var-get total-staked) u1))
    (ok original-owner)
  )
)

(define-public (update-last-claim (token-id uint))
  (let
    (
      (stake-data (unwrap! (map-get? staked-nfts { token-id: token-id }) ERR-NOT-STAKED))
    )
    ;; Only rewards contract can call this
    (asserts! (is-eq contract-caller .stakeflow-rewards-mainnet) ERR-NOT-AUTHORIZED)
    (map-set staked-nfts
      { token-id: token-id }
      (merge stake-data { last-claim: block-height })
    )
    (ok true)
  )
)

;; ---------------------------------------------------------
;; Admin Functions
;; ---------------------------------------------------------

(define-public (set-staking-paused (paused bool))
  (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (ok (var-set staking-paused paused))
  )
)

Functions (11)

FunctionAccessArgs
stake-nftpublictoken-id: uint
get-stake-inforead-onlytoken-id: uint
is-stakedread-onlytoken-id: uint
get-staked-countread-onlystaker: principal
get-total-stakedread-only
get-blocks-stakedread-onlytoken-id: uint
get-stakerread-onlytoken-id: uint
is-staking-pausedread-only
remove-stakepublictoken-id: uint
update-last-claimpublictoken-id: uint
set-staking-pausedpublicpaused: bool