Source Code

;; Education Fund Contract
;; Community education fund for students
;; Halal - investing in knowledge (ilm)
;; Clarity 4 compatible

(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-NOT-FOUND (err u404))

(define-data-var fund-balance uint u0)
(define-data-var student-count uint u0)
(define-data-var total-disbursed uint u0)

(define-map students uint {
  name: (string-utf8 100), institution: (string-utf8 100), program: (string-utf8 100),
  needed: uint, received: uint, gpa: uint, status: (string-ascii 20), enrolled: uint
})
(define-map contributors principal { total: uint, donations: uint })
(define-map disbursements { student-id: uint, index: uint } { amount: uint, purpose: (string-utf8 100), block: uint })
(define-map disbursement-count uint uint)

(define-public (contribute (amount uint))
  (let ((prev (default-to { total: u0, donations: u0 } (map-get? contributors tx-sender))))
    (try! (stx-transfer? amount tx-sender CONTRACT-OWNER))
    (map-set contributors tx-sender { total: (+ (get total prev) amount), donations: (+ (get donations prev) u1) })
    (var-set fund-balance (+ (var-get fund-balance) amount))
    (ok amount)))

(define-public (enroll-student (name (string-utf8 100)) (institution (string-utf8 100)) (program (string-utf8 100)) (needed uint) (gpa uint))
  (let ((id (+ (var-get student-count) u1)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (map-set students id { name: name, institution: institution, program: program, needed: needed, received: u0, gpa: gpa, status: "active", enrolled: stacks-block-height })
    (var-set student-count id) (ok id)))

(define-public (disburse (student-id uint) (amount uint) (purpose (string-utf8 100)))
  (let (
    (student (unwrap! (map-get? students student-id) ERR-NOT-FOUND))
    (idx (default-to u0 (map-get? disbursement-count student-id)))
  )
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (try! (stx-transfer? amount tx-sender CONTRACT-OWNER))
    (map-set disbursements { student-id: student-id, index: idx } { amount: amount, purpose: purpose, block: stacks-block-height })
    (map-set disbursement-count student-id (+ idx u1))
    (map-set students student-id (merge student { received: (+ (get received student) amount) }))
    (var-set fund-balance (- (var-get fund-balance) amount))
    (var-set total-disbursed (+ (var-get total-disbursed) amount))
    (ok amount)))

(define-public (update-gpa (student-id uint) (new-gpa uint))
  (let ((student (unwrap! (map-get? students student-id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (map-set students student-id (merge student { gpa: new-gpa })) (ok true)))

(define-public (graduate-student (student-id uint))
  (let ((student (unwrap! (map-get? students student-id) ERR-NOT-FOUND)))
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
    (map-set students student-id (merge student { status: "graduated" })) (ok true)))

(define-read-only (get-student (id uint)) (map-get? students id))
(define-read-only (get-contributor (who principal)) (map-get? contributors who))
(define-read-only (get-disbursement (student-id uint) (index uint)) (map-get? disbursements { student-id: student-id, index: index }))
(define-read-only (get-fund-balance) (ok (var-get fund-balance)))
(define-read-only (get-total-disbursed) (ok (var-get total-disbursed)))
(define-read-only (get-student-count) (ok (var-get student-count)))

Functions (11)

FunctionAccessArgs
contributepublicamount: uint
enroll-studentpublicname: (string-utf8 100
disbursepublicstudent-id: uint, amount: uint, purpose: (string-utf8 100
update-gpapublicstudent-id: uint, new-gpa: uint
graduate-studentpublicstudent-id: uint
get-studentread-onlyid: uint
get-contributorread-onlywho: principal
get-disbursementread-onlystudent-id: uint, index: uint
get-fund-balanceread-only
get-total-disbursedread-only
get-student-countread-only