Source Code

;; title: invoice-ledger
;; version:
;; summary:
;; description:

;; Impact Sustainability Tracking Smart Contract
;; A comprehensive system for tracking environmental and social impact metrics

;; Constants
(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_UNAUTHORIZED (err u100))
(define-constant ERR_NOT_FOUND (err u101))
(define-constant ERR_INVALID_INPUT (err u102))
(define-constant ERR_ALREADY_EXISTS (err u103))
(define-constant ERR_INVALID_PERIOD (err u104))
(define-constant ERR_INSUFFICIENT_BALANCE (err u105))
(define-constant ERR_INVALID_VERIFICATION (err u106))
(define-constant ERR_EXPIRED (err u107))

;; Impact category constants
(define-constant CARBON_REDUCTION u1)
(define-constant RENEWABLE_ENERGY u2)
(define-constant WASTE_REDUCTION u3)
(define-constant WATER_CONSERVATION u4)
(define-constant BIODIVERSITY u5)
(define-constant SOCIAL_IMPACT u6)

;; Input validation constants
(define-constant MAX_FEE u1000000000) ;; 1000 STX max fee
(define-constant MAX_STAKE u100000000000) ;; 100,000 STX max stake
(define-constant MAX_PROJECT_ID u1000000) ;; Max project ID
(define-constant MAX_RECORD_ID u1000000) ;; Max record ID
(define-constant MAX_MILESTONE_ID u1000) ;; Max milestone ID
(define-constant MAX_REWARD u10000000000) ;; 10,000 STX max reward

;; Data Variables
(define-data-var contract-active bool true)
(define-data-var total-projects uint u0)
(define-data-var verification-fee uint u1000000) ;; 1 STX in microSTX
(define-data-var min-stake-amount uint u5000000) ;; 5 STX minimum stake

;; Data Maps

;; Project registry
(define-map projects
  { project-id: uint }
  {
    owner: principal,
    name: (string-ascii 100),
    description: (string-utf8 500),
    category: uint,
    target-impact: uint,
    current-impact: uint,
    created-at: uint,
    expires-at: uint,
    verified: bool,
    stake-amount: uint,
    active: bool
  }
)

;; Impact records for detailed tracking
(define-map impact-records
  { project-id: uint, record-id: uint }
  {
    reporter: principal,
    impact-value: uint,
    evidence-hash: (string-ascii 64),
    timestamp: uint,
    verified: bool,
    verifier: (optional principal)
  }
)

;; Project impact record counters
(define-map project-record-counts
  { project-id: uint }
  { count: uint }
)

;; Verifier registry
(define-map verifiers
  { verifier: principal }
  {
    reputation: uint,
    total-verifications: uint,
    successful-verifications: uint,
    registered-at: uint,
    active: bool
  }
)

;; Stakeholder balances
(define-map stakeholder-balances
  { stakeholder: principal }
  { balance: uint }
)

;; Project stakeholder tracking
(define-map project-stakeholders
  { project-id: uint, stakeholder: principal }
  { stake-amount: uint, joined-at: uint }
)

;; Impact achievements and milestones
(define-map project-milestones
  { project-id: uint, milestone-id: uint }
  {
    description: (string-utf8 200),
    target-value: uint,
    achieved: bool,
    achieved-at: (optional uint),
    reward-amount: uint
  }
)

;; Milestone counters
(define-map project-milestone-counts
  { project-id: uint }
  { count: uint }
)

;; Utility Functions

;; Get current block height as timestamp
(define-private (get-block-timestamp)
  stacks-block-height
)

;; Validate impact category
(define-private (is-valid-category (category uint))
  (and (>= category u1) (<= category u6))
)

;; Validate project ID
(define-private (is-valid-project-id (project-id uint))
  (and (> project-id u0) (<= project-id MAX_PROJECT_ID))
)

;; Validate record ID
(define-private (is-valid-record-id (record-id uint))
  (and (> record-id u0) (<= record-id MAX_RECORD_ID))
)

;; Validate milestone ID
(define-private (is-valid-milestone-id (milestone-id uint))
  (and (> milestone-id u0) (<= milestone-id MAX_MILESTONE_ID))
)

;; Validate fee amount
(define-private (is-valid-fee (fee uint))
  (and (> fee u0) (<= fee MAX_FEE))
)

;; Validate stake amount
(define-private (is-valid-stake-amount (amount uint))
  (and (> amount u0) (<= amount MAX_STAKE))
)

;; Validate reward amount
(define-private (is-valid-reward-amount (amount uint))
  (<= amount MAX_REWARD)
)

;; Validate string is not empty
(define-private (is-non-empty-string-ascii (str (string-ascii 100)))
  (> (len str) u0)
)

;; Validate UTF8 string is not empty
(define-private (is-non-empty-string-utf8 (str (string-utf8 500)))
  (> (len str) u0)
)

;; Validate UTF8 200 string is not empty
(define-private (is-non-empty-string-utf8-200 (str (string-utf8 200)))
  (> (len str) u0)
)

;; Validate evidence hash
(define-private (is-valid-evidence-hash (hash (string-ascii 64)))
  (and (> (len hash) u0) (<= (len hash) u64))
)

;; Calculate reputation score
(define-private (calculate-reputation (successful uint) (total uint))
  (if (is-eq total u0)
    u0
    (* (/ (* successful u100) total) u10)
  )
)

;; Administrative Functions

;; Update contract settings (owner only)
(define-public (update-verification-fee (new-fee uint))
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_UNAUTHORIZED)
    (asserts! (is-valid-fee new-fee) ERR_INVALID_INPUT)
    (var-set verification-fee new-fee)
    (ok true)
  )
)

(define-public (update-min-stake-amount (new-amount uint))
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_UNAUTHORIZED)
    (asserts! (is-valid-stake-amount new-amount) ERR_INVALID_INPUT)
    (var-set min-stake-amount new-amount)
    (ok true)
  )
)

(define-public (toggle-contract-active)
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_UNAUTHORIZED)
    (var-set contract-active (not (var-get contract-active)))
    (ok (var-get contract-active))
  )
)


;; Impact Reporting Functions

;; Submit impact record
(define-public (submit-impact-record
  (project-id uint)
  (impact-value uint)
  (evidence-hash (string-ascii 64)))
  (let
    (
      (project (unwrap! (map-get? projects { project-id: project-id }) ERR_NOT_FOUND))
      (record-count (default-to u0 (get count (map-get? project-record-counts { project-id: project-id }))))
      (new-record-id (+ record-count u1))
    )
    (asserts! (var-get contract-active) ERR_UNAUTHORIZED)
    (asserts! (is-valid-project-id project-id) ERR_INVALID_INPUT)
    (asserts! (> impact-value u0) ERR_INVALID_INPUT)
    (asserts! (is-valid-evidence-hash evidence-hash) ERR_INVALID_INPUT)
    (asserts! (get active project) ERR_INVALID_INPUT)
    (asserts! (or (is-eq tx-sender (get owner project)) 
                  (is-some (map-get? project-stakeholders { project-id: project-id, stakeholder: tx-sender })))
              ERR_UNAUTHORIZED)
    (asserts! (< (get-block-timestamp) (get expires-at project)) ERR_EXPIRED)
    (asserts! (<= new-record-id MAX_RECORD_ID) ERR_INVALID_INPUT)
    
    ;; Create impact record
    (map-set impact-records
      { project-id: project-id, record-id: new-record-id }
      {
        reporter: tx-sender,
        impact-value: impact-value,
        evidence-hash: evidence-hash,
        timestamp: (get-block-timestamp),
        verified: false,
        verifier: none
      }
    )
    
    ;; Update record count
    (map-set project-record-counts
      { project-id: project-id }
      { count: new-record-id }
    )
    
    (ok new-record-id)
  )
)

;; Verification System

;; Register as verifier
(define-public (register-verifier)
  (begin
    (asserts! (var-get contract-active) ERR_UNAUTHORIZED)
    (asserts! (is-none (map-get? verifiers { verifier: tx-sender })) ERR_ALREADY_EXISTS)
    
    ;; Pay verification registration fee
    (try! (stx-transfer? (var-get verification-fee) tx-sender CONTRACT_OWNER))
    
    (map-set verifiers
      { verifier: tx-sender }
      {
        reputation: u0,
        total-verifications: u0,
        successful-verifications: u0,
        registered-at: (get-block-timestamp),
        active: true
      }
    )
    
    (ok true)
  )
)

;; Verify impact record
(define-public (verify-impact-record (project-id uint) (record-id uint) (approved bool))
  (let
    (
      (verifier-data (unwrap! (map-get? verifiers { verifier: tx-sender }) ERR_UNAUTHORIZED))
      (record (unwrap! (map-get? impact-records { project-id: project-id, record-id: record-id }) ERR_NOT_FOUND))
      (project (unwrap! (map-get? projects { project-id: project-id }) ERR_NOT_FOUND))
    )
    (asserts! (var-get contract-active) ERR_UNAUTHORIZED)
    (asserts! (is-valid-project-id project-id) ERR_INVALID_INPUT)
    (asserts! (is-valid-record-id record-id) ERR_INVALID_INPUT)
    (asserts! (get active verifier-data) ERR_UNAUTHORIZED)
    (asserts! (not (get verified record)) ERR_ALREADY_EXISTS)
    
    ;; Update impact record
    (map-set impact-records
      { project-id: project-id, record-id: record-id }
      (merge record {
        verified: approved,
        verifier: (some tx-sender)
      })
    )
    
    ;; If approved, update project impact
    (if approved
      (map-set projects
        { project-id: project-id }
        (merge project {
          current-impact: (+ (get current-impact project) (get impact-value record))
        })
      )
      true
    )
    
    ;; Update verifier statistics
    (map-set verifiers
      { verifier: tx-sender }
      (merge verifier-data {
        total-verifications: (+ (get total-verifications verifier-data) u1),
        successful-verifications: (if approved 
                                    (+ (get successful-verifications verifier-data) u1)
                                    (get successful-verifications verifier-data)),
        reputation: (calculate-reputation 
                      (if approved 
                        (+ (get successful-verifications verifier-data) u1)
                        (get successful-verifications verifier-data))
                      (+ (get total-verifications verifier-data) u1))
      })
    )
    
    (ok approved)
  )
)

Functions (19)

FunctionAccessArgs
get-block-timestampprivate
is-valid-categoryprivatecategory: uint
is-valid-project-idprivateproject-id: uint
is-valid-record-idprivaterecord-id: uint
is-valid-milestone-idprivatemilestone-id: uint
is-valid-feeprivatefee: uint
is-valid-stake-amountprivateamount: uint
is-valid-reward-amountprivateamount: uint
is-non-empty-string-asciiprivatestr: (string-ascii 100
is-non-empty-string-utf8privatestr: (string-utf8 500
is-non-empty-string-utf8-200privatestr: (string-utf8 200
is-valid-evidence-hashprivatehash: (string-ascii 64
calculate-reputationprivatesuccessful: uint, total: uint
update-verification-feepublicnew-fee: uint
update-min-stake-amountpublicnew-amount: uint
toggle-contract-activepublic
submit-impact-recordpublicproject-id: uint, impact-value: uint, evidence-hash: (string-ascii 64
register-verifierpublic
verify-impact-recordpublicproject-id: uint, record-id: uint, approved: bool