Source Code

;; title: community-scholar
;; version:
;; summary:
;; description:

 ;; Community Scholarship Fund Smart Contract
;; Handles scholarship applications, funding, and disbursement

;; Constants
(define-constant CONTRACT_ADMINISTRATOR tx-sender)
(define-constant ERROR_UNAUTHORIZED_ACCESS (err u1))
(define-constant ERROR_APPLICATION_EXISTS (err u2))
(define-constant ERROR_DONATION_BELOW_MINIMUM (err u3))
(define-constant ERROR_INSUFFICIENT_BALANCE (err u4))
(define-constant ERROR_RECIPIENT_NOT_ELIGIBLE (err u5))
(define-constant ERROR_APPLICATION_PERIOD_CLOSED (err u6))
(define-constant ERROR_INVALID_INPUT (err u7))
(define-constant MINIMUM_DONATION_AMOUNT u1000000) ;; in microSTX (1 STX)
(define-constant MAXIMUM_SCHOLARSHIP_AMOUNT u1000000000) ;; 1000 STX
(define-constant MAXIMUM_GPA u400) ;; 4.00 GPA * 100
(define-constant MAXIMUM_ACADEMIC_YEAR u8)

;; Data Variables
(define-data-var scholarship-pool-balance uint u0)
(define-data-var application-submission-deadline uint u0)
(define-data-var scholarship-disbursement-period uint u0)

;; Data Maps
(define-map DonorRegistry 
    principal 
    {
        cumulative-donation-amount: uint,
        most-recent-donation-block: uint
    }
)

(define-map ScholarshipRecipients
    principal
    {
        recipient-status: (string-ascii 20),
        scholarship-amount: uint,
        academic-performance: uint,
        field-of-study: (string-ascii 50),
        academic-year: uint
    }
)

(define-map ScholarshipApplications
    principal
    {
        applicant-full-name: (string-ascii 50),
        academic-performance: uint,
        field-of-study: (string-ascii 50),
        academic-year: uint,
        requested-scholarship-amount: uint,
        application-status: (string-ascii 20)
    }
)

;; Private Functions
(define-private (is-administrator)
    (is-eq tx-sender CONTRACT_ADMINISTRATOR)
)

(define-private (validate-donation-amount (donation-amount uint))
    (>= donation-amount MINIMUM_DONATION_AMOUNT)
)

(define-private (update-donor-records (donor-address principal) (donation-amount uint))
    (let (
        (current-donor-info (default-to 
            { cumulative-donation-amount: u0, most-recent-donation-block: u0 } 
            (map-get? DonorRegistry donor-address)
        ))
    )
    (map-set DonorRegistry
        donor-address
        {
            cumulative-donation-amount: (+ (get cumulative-donation-amount current-donor-info) donation-amount),
            most-recent-donation-block: stacks-block-height
        }
    )
    )
)

(define-private (validate-applicant-name (name (string-ascii 50)))
    (and (>= (len name) u1) (<= (len name) u50))
)

(define-private (validate-grade-point-average (gpa uint))
    (<= gpa MAXIMUM_GPA)
)

(define-private (validate-selected-major (major (string-ascii 50)))
    (and (>= (len major) u1) (<= (len major) u50))
)

(define-private (validate-current-year (year uint))
    (and (>= year u1) (<= year MAXIMUM_ACADEMIC_YEAR))
)

(define-private (validate-requested-amount (amount uint))
    (<= amount MAXIMUM_SCHOLARSHIP_AMOUNT)
)

(define-private (validate-and-sanitize-application
    (applicant-name (string-ascii 50))
    (grade-point-average uint)
    (selected-major (string-ascii 50))
    (current-year uint)
    (requested-amount uint)
)
    (begin
        ;; Perform all validations first
        (asserts! (validate-applicant-name applicant-name) ERROR_INVALID_INPUT)
        (asserts! (validate-grade-point-average grade-point-average) ERROR_INVALID_INPUT)
        (asserts! (validate-selected-major selected-major) ERROR_INVALID_INPUT)
        (asserts! (validate-current-year current-year) ERROR_INVALID_INPUT)
        (asserts! (validate-requested-amount requested-amount) ERROR_INVALID_INPUT)

        ;; Return validated data structure
        (ok {
            applicant-name: applicant-name,
            grade-point-average: grade-point-average,
            selected-major: selected-major,
            current-year: current-year,
            requested-amount: requested-amount
        })
    )
)

(define-private (validate-principal (address principal))
    (match (principal-destruct? address)
        success true
        error false
    )
)



(define-public (submit-scholarship-application 
    (applicant-name (string-ascii 50))
    (grade-point-average uint)
    (selected-major (string-ascii 50))
    (current-year uint)
    (requested-amount uint)
)
    (let (
        (existing-application (map-get? ScholarshipApplications tx-sender))
    )
    (if (is-some existing-application)
        ERROR_APPLICATION_EXISTS
        (if (> stacks-block-height (var-get application-submission-deadline))
            ERROR_APPLICATION_PERIOD_CLOSED
            (match (validate-and-sanitize-application applicant-name grade-point-average selected-major current-year requested-amount)
                validated-data (begin
                    (map-set ScholarshipApplications
                        tx-sender
                        {
                            applicant-full-name: (get applicant-name validated-data),
                            academic-performance: (get grade-point-average validated-data),
                            field-of-study: (get selected-major validated-data),
                            academic-year: (get current-year validated-data),
                            requested-scholarship-amount: (get requested-amount validated-data),
                            application-status: "PENDING"
                        }
                    )
                    (ok true)
                )
                error ERROR_INVALID_INPUT
            )
        )
    ))
)

(define-public (evaluate-scholarship-application (applicant-address principal) (is-approved bool))
    (begin
        (asserts! (is-administrator) ERROR_UNAUTHORIZED_ACCESS)
        (asserts! (validate-principal applicant-address) ERROR_INVALID_INPUT)
        (match (map-get? ScholarshipApplications applicant-address)
            current-application
            (begin
                (map-set ScholarshipApplications
                    applicant-address
                    (merge current-application
                        {application-status: (if is-approved "APPROVED" "REJECTED")}
                    )
                )
                (if is-approved
                    (map-set ScholarshipRecipients
                        applicant-address
                        {
                            recipient-status: "ACTIVE",
                            scholarship-amount: (get requested-scholarship-amount current-application),
                            academic-performance: (get academic-performance current-application),
                            field-of-study: (get field-of-study current-application),
                            academic-year: (get academic-year current-application)
                        }
                    )
                    true
                )
                (ok true)
            )
            (err u404)
        )
    )
)



;; Read-Only Functions
(define-read-only (get-scholarship-fund-balance)
    (ok (var-get scholarship-pool-balance))
)

(define-read-only (get-donor-details (donor-address principal))
    (ok (map-get? DonorRegistry donor-address))
)

(define-read-only (get-application-details (applicant-address principal))
    (ok (map-get? ScholarshipApplications applicant-address))
)

(define-read-only (get-recipient-details (recipient-address principal))
    (ok (map-get? ScholarshipRecipients recipient-address))
)

;; Administrative Functions
(define-public (update-application-deadline (new-deadline-block uint))
    (begin
        (asserts! (is-administrator) ERROR_UNAUTHORIZED_ACCESS)
        (asserts! (> new-deadline-block stacks-block-height) ERROR_INVALID_INPUT)
        (var-set application-submission-deadline new-deadline-block)
        (ok true)
    )
)

(define-public (update-disbursement-period (new-disbursement-block uint))
    (begin
        (asserts! (is-administrator) ERROR_UNAUTHORIZED_ACCESS)
        (asserts! (> new-disbursement-block stacks-block-height) ERROR_INVALID_INPUT)
        (var-set scholarship-disbursement-period new-disbursement-block)
        (ok true)
    )
)

Functions (18)

FunctionAccessArgs
is-administratorprivate
validate-donation-amountprivatedonation-amount: uint
update-donor-recordsprivatedonor-address: principal, donation-amount: uint
validate-applicant-nameprivatename: (string-ascii 50
validate-grade-point-averageprivategpa: uint
validate-selected-majorprivatemajor: (string-ascii 50
validate-current-yearprivateyear: uint
validate-requested-amountprivateamount: uint
validate-and-sanitize-applicationprivateapplicant-name: (string-ascii 50
validate-principalprivateaddress: principal
submit-scholarship-applicationpublicapplicant-name: (string-ascii 50
evaluate-scholarship-applicationpublicapplicant-address: principal, is-approved: bool
get-scholarship-fund-balanceread-only
get-donor-detailsread-onlydonor-address: principal
get-application-detailsread-onlyapplicant-address: principal
get-recipient-detailsread-onlyrecipient-address: principal
update-application-deadlinepublicnew-deadline-block: uint
update-disbursement-periodpublicnew-disbursement-block: uint