Source Code

;; title: role-based-access
;; version:
;; summary:
;; description:

;; Decentralized Information Marketplace Smart Contract
;; A trustless platform enabling users to post information requests with monetary rewards,
;; allowing knowledge providers to submit solutions and earn STX tokens upon selection.
;; Features automated escrow, fair dispute resolution, and community-driven knowledge sharing.

;; ERROR CONSTANTS

(define-constant ERR-OWNER-ONLY-OPERATION (err u100))
(define-constant ERR-INFORMATION-REQUEST-NOT-FOUND (err u101))
(define-constant ERR-UNAUTHORIZED-ACCESS (err u102))
(define-constant ERR-INVALID-REWARD-AMOUNT (err u103))
(define-constant ERR-REQUEST-ALREADY-CLOSED (err u104))
(define-constant ERR-REQUEST-HAS-EXPIRED (err u105))
(define-constant ERR-DUPLICATE-SUBMISSION-ATTEMPT (err u106))
(define-constant ERR-INSUFFICIENT-CONTRACT-BALANCE (err u107))
(define-constant ERR-INVALID-INPUT-PARAMETERS (err u108))
(define-constant ERR-REQUEST-HAS-ACTIVE-SUBMISSIONS (err u109))
(define-constant ERR-NO-SUBMISSIONS-FOUND (err u110))
(define-constant ERR-SUBMISSION-DOES-NOT-EXIST (err u111))

;; CONFIGURATION CONSTANTS

(define-constant contract-administrator tx-sender)
(define-constant maximum-title-length u128)
(define-constant maximum-description-length u512)
(define-constant maximum-solution-content-length u1024)
(define-constant maximum-user-requests-limit u100)
(define-constant maximum-user-submissions-limit u100)
(define-constant default-platform-commission-rate u250) ;; 2.5% in basis points
(define-constant minimum-information-request-reward u1000000) ;; 1 STX
(define-constant maximum-request-duration-blocks u4320) ;; 30 days (144 blocks/day)
(define-constant basis-points-denominator u10000)

;; STATE VARIABLES

(define-data-var information-request-counter uint u0)
(define-data-var platform-commission-rate uint default-platform-commission-rate)
(define-data-var minimum-reward-threshold uint minimum-information-request-reward)
(define-data-var maximum-duration-limit uint maximum-request-duration-blocks)

;; DATA STRUCTURES

;; Main information request registry
(define-map information-requests-registry
    uint
    {
        request-creator: principal,
        request-title: (string-ascii 128),
        detailed-description: (string-utf8 512),
        reward-pool-amount: uint,
        expiration-block-height: uint,
        current-status: (string-ascii 16),
        selected-solution-provider: (optional principal),
        request-creation-block: uint
    }
)

;; Solutions submitted for each request
(define-map solution-submissions-registry
    {information-request-id: uint, solution-provider: principal}
    {
        solution-content-data: (string-utf8 1024),
        submission-block-height: uint,
        is-selected-solution: bool
    }
)

;; Track submission counts per request
(define-map request-submission-counters
    uint
    uint
)

;; User's created requests tracking
(define-map user-created-requests-log
    principal
    (list 100 uint)
)

;; User's submission history tracking
(define-map user-submission-history-log
    principal
    (list 100 {request-id: uint, submission-timestamp: uint})
)

;; READ-ONLY QUERY FUNCTIONS

(define-read-only (get-information-request-details (request-id uint))
    (map-get? information-requests-registry request-id)
)

(define-read-only (get-solution-submission-details (request-id uint) (provider principal))
    (map-get? solution-submissions-registry {information-request-id: request-id, solution-provider: provider})
)

(define-read-only (get-total-submissions-for-request (request-id uint))
    (default-to u0 (map-get? request-submission-counters request-id))
)

(define-read-only (get-user-created-requests-list (user-address principal))
    (default-to (list) (map-get? user-created-requests-log user-address))
)

(define-read-only (get-user-submission-history (user-address principal))
    (default-to (list) (map-get? user-submission-history-log user-address))
)

(define-read-only (get-current-platform-commission-rate)
    (var-get platform-commission-rate)
)

(define-read-only (get-minimum-reward-threshold)
    (var-get minimum-reward-threshold)
)

(define-read-only (get-total-information-requests-count)
    (var-get information-request-counter)
)

(define-read-only (check-if-request-is-active (request-id uint))
    (match (map-get? information-requests-registry request-id)
        request-details
        (and 
            (is-eq (get current-status request-details) "active")
            (< stacks-block-height (get expiration-block-height request-details))
        )
        false
    )
)

(define-read-only (calculate-platform-commission-fee (reward-amount uint))
    (/ (* reward-amount (var-get platform-commission-rate)) basis-points-denominator)
)

(define-read-only (calculate-final-solution-provider-payout (reward-amount uint))
    (- reward-amount (calculate-platform-commission-fee reward-amount))
)

;; INTERNAL UTILITY FUNCTIONS

(define-private (append-request-to-user-log (user-address principal) (request-id uint))
    (let 
        (
            (existing-user-requests (get-user-created-requests-list user-address))
            (updated-list (unwrap! (as-max-len? (append existing-user-requests request-id) u100) 
                (err u999)))
        )
        (map-set user-created-requests-log user-address updated-list)
        (ok true)
    )
)

(define-private (append-submission-to-user-history (user-address principal) (request-id uint))
    (let 
        (
            (existing-submission-history (get-user-submission-history user-address))
            (new-submission-entry {request-id: request-id, submission-timestamp: stacks-block-height})
            (updated-list (unwrap! (as-max-len? (append existing-submission-history new-submission-entry) u100) 
                (err u999)))
        )
        (map-set user-submission-history-log user-address updated-list)
        (ok true)
    )
)

(define-private (update-information-request-status 
    (request-id uint) 
    (new-status (string-ascii 16)) 
    (solution-provider-address (optional principal))
)
    (match (map-get? information-requests-registry request-id)
        existing-request-data
        (begin
            (map-set information-requests-registry request-id 
                (merge existing-request-data {
                    current-status: new-status, 
                    selected-solution-provider: solution-provider-address
                })
            )
            (ok true)
        )
        (err u999)
    )
)

(define-private (validate-principal-not-empty (address principal))
    (not (is-eq address 'SP000000000000000000002Q6VF78))
)

(define-private (validate-amount-greater-than-zero (amount uint))
    (> amount u0)
)

(define-private (validate-input-string-length (input-string (string-utf8 1024)) (max-length uint))
    (and (> (len input-string) u0) (<= (len input-string) max-length))
)

(define-private (validate-ascii-string-length (input-string (string-ascii 128)) (max-length uint))
    (and (> (len input-string) u0) (<= (len input-string) max-length))
)

;; CORE BUSINESS LOGIC FUNCTIONS


(define-public (submit-solution-for-request 
    (request-id uint) 
    (solution-content (string-utf8 1024))
)
    (let 
        (
            (request-details (unwrap! (map-get? information-requests-registry request-id) ERR-INFORMATION-REQUEST-NOT-FOUND))
            (submission-identifier {information-request-id: request-id, solution-provider: tx-sender})
        )
        ;; Verify request is still active and not expired
        (asserts! (check-if-request-is-active request-id) ERR-REQUEST-ALREADY-CLOSED)
        
        ;; Validate solution content
        (asserts! (validate-input-string-length solution-content u1024) ERR-INVALID-INPUT-PARAMETERS)
        
        ;; Prevent duplicate submissions from same user
        (asserts! (is-none (map-get? solution-submissions-registry submission-identifier)) ERR-DUPLICATE-SUBMISSION-ATTEMPT)
        
        ;; Record the solution submission
        (map-set solution-submissions-registry submission-identifier {
            solution-content-data: solution-content,
            submission-block-height: stacks-block-height,
            is-selected-solution: false
        })
        
        ;; Increment submission counter for this request
        (map-set request-submission-counters request-id 
            (+ (get-total-submissions-for-request request-id) u1)
        )
        
        ;; Update user's submission history
        (try! (append-submission-to-user-history tx-sender request-id))
        
        (ok true)
    )
)

Functions (19)

FunctionAccessArgs
get-information-request-detailsread-onlyrequest-id: uint
get-solution-submission-detailsread-onlyrequest-id: uint, provider: principal
get-total-submissions-for-requestread-onlyrequest-id: uint
get-user-created-requests-listread-onlyuser-address: principal
get-user-submission-historyread-onlyuser-address: principal
get-current-platform-commission-rateread-only
get-minimum-reward-thresholdread-only
get-total-information-requests-countread-only
check-if-request-is-activeread-onlyrequest-id: uint
calculate-platform-commission-feeread-onlyreward-amount: uint
calculate-final-solution-provider-payoutread-onlyreward-amount: uint
append-request-to-user-logprivateuser-address: principal, request-id: uint
append-submission-to-user-historyprivateuser-address: principal, request-id: uint
update-information-request-statusprivaterequest-id: uint, new-status: (string-ascii 16
validate-principal-not-emptyprivateaddress: principal
validate-amount-greater-than-zeroprivateamount: uint
validate-input-string-lengthprivateinput-string: (string-utf8 1024
validate-ascii-string-lengthprivateinput-string: (string-ascii 128
submit-solution-for-requestpublicrequest-id: uint, solution-content: (string-utf8 1024