Source Code

;; Time Token Fungible Token (Clarity 4)
;; SIP-010 compliant fungible token for tradeable time credits
;; Uses stacks-block-time for staking reward calculations

;; traits
;; (impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

;; token definitions
(define-fungible-token time-token)

;; constants
(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_UNAUTHORIZED (err u3001))
(define-constant ERR_INSUFFICIENT_BALANCE (err u3002))
(define-constant ERR_INVALID_AMOUNT (err u3003))

(define-constant TOKEN_NAME "Time Token")
(define-constant TOKEN_SYMBOL "TIME")
(define-constant TOKEN_DECIMALS u6)
(define-constant MICRO_TIME_PER_HOUR u1000000)

;; data vars
(define-data-var total-supply uint u0)
(define-data-var staking-enabled bool true)
(define-data-var min-stake-amount uint u10000000)

;; data maps
(define-map stakes
    principal
    {
        amount: uint,
        staked-at: uint,
        last-reward-claim: uint,
        total-rewards: uint
    })

(define-map allowances
    { owner: principal, spender: principal }
    uint)

;; public functions
(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
    (begin
        (asserts! (or (is-eq tx-sender sender) (>= (get-allowance-or-default sender tx-sender) amount)) ERR_UNAUTHORIZED)
        (asserts! (> amount u0) ERR_INVALID_AMOUNT)
        (try! (ft-transfer? time-token amount sender recipient))
        (match memo m (print m) 0x)
        (ok true)))

(define-public (get-name)
    (ok TOKEN_NAME))

(define-public (get-symbol)
    (ok TOKEN_SYMBOL))

(define-public (get-decimals)
    (ok TOKEN_DECIMALS))

(define-public (get-balance (account principal))
    (ok (ft-get-balance time-token account)))

(define-public (get-total-supply)
    (ok (ft-get-supply time-token)))

(define-public (get-token-uri)
    (ok (some "https://timebank.io/tokens/time-token")))

(define-public (mint (recipient principal) (amount uint))
    (begin
        (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_UNAUTHORIZED)
        (asserts! (> amount u0) ERR_INVALID_AMOUNT)
        (try! (ft-mint? time-token amount recipient))
        (ok true)))

(define-public (burn (amount uint))
    (begin
        (asserts! (> amount u0) ERR_INVALID_AMOUNT)
        (try! (ft-burn? time-token amount tx-sender))
        (ok true)))

(define-public (stake (amount uint))
    (begin
        (asserts! (var-get staking-enabled) ERR_UNAUTHORIZED)
        (asserts! (>= amount (var-get min-stake-amount)) ERR_INVALID_AMOUNT)
        (let ((current-stake (default-to
            { amount: u0, staked-at: u0, last-reward-claim: u0, total-rewards: u0 }
            (map-get? stakes tx-sender))))
            (try! (ft-burn? time-token amount tx-sender))
            (map-set stakes tx-sender {
                amount: (+ (get amount current-stake) amount),
                staked-at: stacks-block-time,
                last-reward-claim: stacks-block-time,
                total-rewards: (get total-rewards current-stake)
            }))
        (ok true)))

(define-public (unstake (amount uint))
    (let ((stake-data (unwrap! (map-get? stakes tx-sender) ERR_UNAUTHORIZED)))
        (asserts! (>= (get amount stake-data) amount) ERR_INSUFFICIENT_BALANCE)
        (try! (ft-mint? time-token amount tx-sender))
        (if (is-eq (get amount stake-data) amount)
            (map-delete stakes tx-sender)
            (map-set stakes tx-sender (merge stake-data {
                amount: (- (get amount stake-data) amount)
            })))
        (ok true)))

(define-public (approve (spender principal) (amount uint))
    (begin
        (map-set allowances { owner: tx-sender, spender: spender } amount)
        (ok true)))

;; read only functions
(define-read-only (get-allowance (owner principal) (spender principal))
    (ok (get-allowance-or-default owner spender)))

(define-read-only (get-stake-info (staker principal))
    (ok (map-get? stakes staker)))

;; private functions
(define-private (get-allowance-or-default (owner principal) (spender principal))
    (default-to u0 (map-get? allowances { owner: owner, spender: spender })))

Functions (15)

FunctionAccessArgs
transferpublicamount: uint, sender: principal, recipient: principal, memo: (optional (buff 34
get-namepublic
get-symbolpublic
get-decimalspublic
get-balancepublicaccount: principal
get-total-supplypublic
get-token-uripublic
mintpublicrecipient: principal, amount: uint
burnpublicamount: uint
stakepublicamount: uint
unstakepublicamount: uint
approvepublicspender: principal, amount: uint
get-allowanceread-onlyowner: principal, spender: principal
get-stake-inforead-onlystaker: principal
get-allowance-or-defaultprivateowner: principal, spender: principal