Source Code

;; Title: BitFlow - Smart Bitcoin Payment Request Protocol
;;
;; Summary: A revolutionary trustless payment infrastructure that transforms
;; Bitcoin commerce through intelligent payment tags and automated
;; settlement on Stacks Layer 2, enabling seamless peer-to-peer
;; transactions with time-bound smart contracts.
;;
;; Description: BitFlow redefines the future of Bitcoin commerce by creating
;; an advanced decentralized payment request ecosystem. The protocol
;; empowers merchants, freelancers, service providers, and individuals
;; to generate sophisticated time-bound payment tags with customizable
;; parameters including recipient designation, precise amounts, and
;; contextual memos. By harnessing the power of sBTC for instantaneous
;; settlement while preserving Bitcoin's uncompromising security model
;; through Stacks Layer 2 architecture, BitFlow eliminates traditional
;; payment intermediaries and creates a truly sovereign financial
;; experience. The protocol features intelligent expiration management,
;; comprehensive indexing systems, and robust state tracking to ensure
;; reliable and efficient payment processing at scale.

;; ERROR CODES & SYSTEM CONSTANTS

;; Core System Error Definitions
(define-constant ERR-TAG-EXISTS u100)
(define-constant ERR-NOT-PENDING u101)
(define-constant ERR-INSUFFICIENT-FUNDS u102)
(define-constant ERR-NOT-FOUND u103)
(define-constant ERR-UNAUTHORIZED u104)
(define-constant ERR-EXPIRED u105)
(define-constant ERR-INVALID-AMOUNT u106)
(define-constant ERR-EMPTY-MEMO u107)
(define-constant ERR-MAX-EXPIRATION-EXCEEDED u108)
(define-constant ERR-INVALID-RECIPIENT u109)
(define-constant ERR-SELF-PAYMENT u110)

;; Payment Tag Lifecycle State Constants
(define-constant STATE-PENDING "pending")
(define-constant STATE-PAID "paid")
(define-constant STATE-EXPIRED "expired")
(define-constant STATE-CANCELED "canceled")

;; PROTOCOL CONFIGURATION & INTEGRATION

;; sBTC Token Contract Integration
;; Production mainnet address - update during deployment
(define-constant SBTC-CONTRACT 'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token)

;; Protocol Administrator
(define-constant CONTRACT-DEPLOYER tx-sender)

;; Protocol Operational Limits & Security Constraints
(define-constant MAX-EXPIRATION-BLOCKS u4320) ;; 30 days (~10 min/block)
(define-constant MAX-TAGS-PER-USER u100) ;; Efficient indexing limit
(define-constant MIN-PAYMENT-AMOUNT u1000) ;; 0.00001 sBTC spam prevention

;; DATA STRUCTURES & PERSISTENT STORAGE

;; Core Payment Tag Registry
(define-map payment-tags
  { id: uint }
  {
    creator: principal,
    recipient: principal,
    amount: uint,
    created-at: uint,
    expires-at: uint,
    memo: (optional (string-ascii 256)),
    state: (string-ascii 16),
    payment-tx: (optional (buff 32)),
    payment-block: (optional uint),
  }
)

;; Creator Indexing for Efficient Query Operations
(define-map creator-index
  { creator: principal }
  {
    tag-ids: (list 100 uint),
    count: uint,
  }
)

;; Recipient Indexing for Payment Tracking & Analytics
(define-map recipient-index
  { recipient: principal }
  {
    tag-ids: (list 100 uint),
    count: uint,
  }
)

;; Protocol Analytics & Performance Metrics
(define-map contract-stats
  { key: (string-ascii 32) }
  { value: uint }
)

;; STATE VARIABLES

(define-data-var tag-counter uint u0)
(define-data-var contract-paused bool false)

;; INTERNAL HELPER FUNCTIONS

;; Add Payment Tag to Creator's Index
(define-private (add-to-creator-index
    (creator principal)
    (tag-id uint)
  )
  (let (
      (current-data (default-to {
        tag-ids: (list),
        count: u0,
      }
        (map-get? creator-index { creator: creator })
      ))
      (current-list (get tag-ids current-data))
      (current-count (get count current-data))
    )
    (match (as-max-len? (append current-list tag-id) u100)
      new-list (begin
        (map-set creator-index { creator: creator } {
          tag-ids: new-list,
          count: (+ current-count u1),
        })
        true
      )
      false
    )
  )
)

;; Add Payment Tag to Recipient's Index
(define-private (add-to-recipient-index
    (recipient principal)
    (tag-id uint)
  )
  (let (
      (current-data (default-to {
        tag-ids: (list),
        count: u0,
      }
        (map-get? recipient-index { recipient: recipient })
      ))
      (current-list (get tag-ids current-data))
      (current-count (get count current-data))
    )
    (match (as-max-len? (append current-list tag-id) u100)
      new-list (begin
        (map-set recipient-index { recipient: recipient } {
          tag-ids: new-list,
          count: (+ current-count u1),
        })
        true
      )
      false
    )
  )
)

;; Expiration Validation Logic
(define-private (is-tag-expired (expires-at uint))
  (>= stacks-block-height expires-at)
)

;; Protocol Metrics Tracking
(define-private (increment-stat (stat-key (string-ascii 32)))
  (let ((current-value (default-to u0 (get value (map-get? contract-stats { key: stat-key })))))
    (map-set contract-stats { key: stat-key } { value: (+ current-value u1) })
  )
)

;; READ-ONLY FUNCTIONS - QUERY INTERFACE

;; Get Current Payment Tag Counter
(define-read-only (get-tag-counter)
  (var-get tag-counter)
)

;; Retrieve Specific Payment Tag Details
(define-read-only (get-payment-tag (tag-id uint))
  (match (map-get? payment-tags { id: tag-id })
    tag-data (ok tag-data)
    (err ERR-NOT-FOUND)
  )
)

;; Get All Payment Tags Created by User
(define-read-only (get-creator-tags (creator principal))
  (match (map-get? creator-index { creator: creator })
    index-data (ok (get tag-ids index-data))
    (ok (list))
  )
)

;; Get All Payment Tags Where User is Recipient
(define-read-only (get-recipient-tags (recipient principal))
  (match (map-get? recipient-index { recipient: recipient })
    index-data (ok (get tag-ids index-data))
    (ok (list))
  )
)

;; Check if Payment Tag is Eligible for Expiration
(define-read-only (can-expire-tag (tag-id uint))
  (match (map-get? payment-tags { id: tag-id })
    tag-data (if (and
        (is-eq (get state tag-data) STATE-PENDING)
        (is-tag-expired (get expires-at tag-data))
      )
      (ok true)
      (ok false)
    )
    (err ERR-NOT-FOUND)
  )
)

;; Retrieve Protocol Statistics
(define-read-only (get-contract-stats (stat-key (string-ascii 32)))
  (match (map-get? contract-stats { key: stat-key })
    stat-data (ok (get value stat-data))
    (ok u0)
  )
)

;; Check Protocol Operational Status
(define-read-only (is-contract-paused)
  (var-get contract-paused)
)

;; Batch Retrieve Multiple Payment Tags
(define-read-only (get-multiple-tags (tag-ids (list 20 uint)))
  (ok (map get-tag-safe tag-ids))
)

;; Safe Tag Retrieval Helper
(define-private (get-tag-safe (tag-id uint))
  (map-get? payment-tags { id: tag-id })
)

;; PUBLIC FUNCTIONS - CORE PROTOCOL OPERATIONS

;; Create New Payment Request Tag
(define-public (create-payment-tag
    (recipient principal)
    (amount uint)
    (expires-in-blocks uint)
    (memo (optional (string-ascii 256)))
  )
  (let (
      (new-tag-id (+ (var-get tag-counter) u1))
      (expiration-block (+ stacks-block-height expires-in-blocks))
    )
    (begin
      ;; Protocol Status Validation
      (asserts! (not (var-get contract-paused)) (err ERR-UNAUTHORIZED))
      
      ;; Input Parameter Validation
      (asserts! (>= amount MIN-PAYMENT-AMOUNT) (err ERR-INVALID-AMOUNT))
      (asserts! (<= expires-in-blocks MAX-EXPIRATION-BLOCKS)
        (err ERR-MAX-EXPIRATION-EXCEEDED)
      )
      (asserts! (> expires-in-blocks u0) (err ERR-INVALID-AMOUNT))
      (asserts! (not (is-eq tx-sender recipient)) (err ERR-SELF-PAYMENT))
      
      ;; Optional Memo Validation
      (match memo
        some-memo (asserts! (> (len some-memo) u0) (err ERR-EMPTY-MEMO))
        true
      )
      
      ;; Create Payment Tag Record
      (map-set payment-tags { id: new-tag-id } {
        creator: tx-sender,
        recipient: recipient,
        amount: amount,
        created-at: stacks-block-height,
        expires-at: expiration-block,
        memo: memo,
        state: STATE-PENDING,
        payment-tx: none,
        payment-block: none,
      })
      
      ;; Update Protocol State
      (var-set tag-counter new-tag-id)
      (add-to-creator-index tx-sender new-tag-id)
      (add-to-recipient-index recipient new-tag-id)
      (increment-stat "tags-created")
      
      ;; Emit Creation Event
      (print {
        event: "payment-tag-created",
        tag-id: new-tag-id,
        creator: tx-sender,
        recipient: recipient,
        amount: amount,
        expires-at: expiration-block,
        memo: memo,
      })
      
      (ok new-tag-id)
    )
  )
)

;; Execute Payment Tag Settlement
(define-public (fulfill-payment-tag (tag-id uint))
  (let ((tag-data (unwrap! (map-get? payment-tags { id: tag-id }) (err ERR-NOT-FOUND))))
    (begin
      ;; Protocol Status Validation
      (asserts! (not (var-get contract-paused)) (err ERR-UNAUTHORIZED))
      
      ;; Input Parameter Validation
      (asserts! (> tag-id u0) (err ERR-INVALID-AMOUNT))
      (asserts! (<= tag-id (var-get tag-counter)) (err ERR-NOT-FOUND))
      
      ;; Payment Tag State Validation
      (asserts! (is-eq (get state tag-data) STATE-PENDING) (err ERR-NOT-PENDING))
      (asserts! (< stacks-block-height (get expires-at tag-data))
        (err ERR-EXPIRED)
      )
      
      ;; Execute sBTC Transfer
      (try! (contract-call? SBTC-CONTRACT transfer (get amount tag-data) tx-sender
        (get recipient tag-data) none
      ))
      
      ;; Update Payment Tag State
      (map-set payment-tags { id: tag-id }
        (merge tag-data {
          state: STATE-PAID,
          payment-block: (some stacks-block-height),
        })
      )
      
      ;; Update Protocol Metrics
      (increment-stat "tags-fulfilled")
      
      ;; Emit Fulfillment Event
      (print {
        event: "payment-tag-fulfilled",
        tag-id: tag-id,
        payer: tx-sender,
        recipient: (get recipient tag-data),
        amount: (get amount tag-data),
        payment-block: stacks-block-height,
      })
      
      (ok tag-id)
    )
  )
)

;; Cancel Payment Request (Creator Only)
(define-public (cancel-payment-tag (tag-id uint))
  (let ((tag-data (unwrap! (map-get? payment-tags { id: tag-id }) (err ERR-NOT-FOUND))))
    (begin
      ;; Input Parameter Validation
      (asserts! (> tag-id u0) (err ERR-INVALID-AMOUNT))
      (asserts! (<= tag-id (var-get tag-counter)) (err ERR-NOT-FOUND))
      
      ;; Authorization Validation
      (asserts! (is-eq tx-sender (get creator tag-data)) (err ERR-UNAUTHORIZED))
      
      ;; State Validation
      (asserts! (is-eq (get state tag-data) STATE-PENDING) (err ERR-NOT-PENDING))
      
      ;; Update Payment Tag State
      (map-set payment-tags { id: tag-id }
        (merge tag-data { state: STATE-CANCELED })
      )
      
      ;; Update Protocol Metrics
      (increment-stat "tags-canceled")
      
      ;; Emit Cancellation Event
      (print {
        event: "payment-tag-canceled",
        tag-id: tag-id,
        creator: tx-sender,
      })
      
      (ok tag-id)
    )
  )
)

;; Mark Expired Payment Tag (Public Function)
(define-public (expire-payment-tag (tag-id uint))
  (let ((tag-data (unwrap! (map-get? payment-tags { id: tag-id }) (err ERR-NOT-FOUND))))
    (begin
      ;; Input Parameter Validation
      (asserts! (> tag-id u0) (err ERR-INVALID-AMOUNT))
      (asserts! (<= tag-id (var-get tag-counter)) (err ERR-NOT-FOUND))
      
      ;; Expiration State Validation
      (asserts! (is-eq (get state tag-data) STATE-PENDING) (err ERR-NOT-PENDING))
      (asserts! (is-tag-expired (get expires-at tag-data)) (err ERR-EXPIRED))
      
      ;; Update Payment Tag State
      (map-set payment-tags { id: tag-id }
        (merge tag-data { state: STATE-EXPIRED })
      )
      
      ;; Update Protocol Metrics
      (increment-stat "tags-expired")
      
      ;; Emit Expiration Event
      (print {
        event: "payment-tag-expired",
        tag-id: tag-id,
        expired-by: tx-sender,
      })
      
      (ok tag-id)
    )
  )
)

;; ADMINISTRATIVE FUNCTIONS - PROTOCOL GOVERNANCE

;; Emergency Protocol Pause Toggle (Deployer Only)
(define-public (toggle-contract-pause)
  (begin
    (asserts! (is-eq tx-sender CONTRACT-DEPLOYER) (err ERR-UNAUTHORIZED))
    (var-set contract-paused (not (var-get contract-paused)))
    
    (print {
      event: "contract-pause-toggled",
      paused: (var-get contract-paused),
    })
    
    (ok (var-get contract-paused))
  )
)

;; Protocol Information & Metadata
(define-read-only (get-contract-info)
  (ok {
    name: "BitFlow - Smart Bitcoin Payment Request Protocol",
    version: "1.0.0",
    deployer: CONTRACT-DEPLOYER,
    total-tags: (var-get tag-counter),
    paused: (var-get contract-paused),
    description: "Revolutionary trustless Bitcoin payment infrastructure on Stacks Layer 2",
  })
)

Functions (17)

FunctionAccessArgs
is-tag-expiredprivateexpires-at: uint
increment-statprivatestat-key: (string-ascii 32
get-tag-counterread-only
get-payment-tagread-onlytag-id: uint
get-creator-tagsread-onlycreator: principal
get-recipient-tagsread-onlyrecipient: principal
can-expire-tagread-onlytag-id: uint
get-contract-statsread-onlystat-key: (string-ascii 32
is-contract-pausedread-only
get-multiple-tagsread-onlytag-ids: (list 20 uint
get-tag-safeprivatetag-id: uint
create-payment-tagpublicrecipient: principal, amount: uint, expires-in-blocks: uint, memo: (optional (string-ascii 256
fulfill-payment-tagpublictag-id: uint
cancel-payment-tagpublictag-id: uint
expire-payment-tagpublictag-id: uint
toggle-contract-pausepublic
get-contract-inforead-only