Source Code

;; Rent Payment Contract
;; On-chain rent payment tracking
;; Halal - fair housing
;; Clarity 4 compatible

(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-NOT-FOUND (err u404))
(define-constant ERR-ALREADY-PAID (err u405))
(define-constant ERR-LEASE-INACTIVE (err u406))

(define-data-var lease-count uint u0)
(define-data-var total-collected uint u0)

(define-map leases uint {
  landlord: principal, tenant: principal, monthly-rent: uint,
  start-block: uint, end-block: uint, payments-made: uint, active: bool
})
(define-map rent-payments { lease-id: uint, period: uint } { amount: uint, paid-at: uint })

(define-public (create-lease (tenant principal) (monthly-rent uint) (duration-months uint))
  (let ((id (+ (var-get lease-count) u1)))
    (map-set leases id {
      landlord: tx-sender, tenant: tenant, monthly-rent: monthly-rent,
      start-block: stacks-block-height, end-block: (+ stacks-block-height (* duration-months u4320)),
      payments-made: u0, active: true
    })
    (var-set lease-count id) (ok id)))

(define-public (pay-rent (lease-id uint))
  (let (
    (lease (unwrap! (map-get? leases lease-id) ERR-NOT-FOUND))
    (period (get payments-made lease))
  )
    (asserts! (is-eq tx-sender (get tenant lease)) ERR-NOT-AUTHORIZED)
    (asserts! (get active lease) ERR-LEASE-INACTIVE)
    (asserts! (is-none (map-get? rent-payments { lease-id: lease-id, period: period })) ERR-ALREADY-PAID)
    (try! (stx-transfer? (get monthly-rent lease) tx-sender (get landlord lease)))
    (map-set rent-payments { lease-id: lease-id, period: period } { amount: (get monthly-rent lease), paid-at: stacks-block-height })
    (map-set leases lease-id (merge lease { payments-made: (+ period u1) }))
    (var-set total-collected (+ (var-get total-collected) (get monthly-rent lease)))
    (ok (+ period u1))))

(define-public (terminate-lease (lease-id uint))
  (let ((lease (unwrap! (map-get? leases lease-id) ERR-NOT-FOUND)))
    (asserts! (or (is-eq tx-sender (get landlord lease)) (is-eq tx-sender (get tenant lease))) ERR-NOT-AUTHORIZED)
    (map-set leases lease-id (merge lease { active: false })) (ok true)))

(define-read-only (get-lease (id uint)) (map-get? leases id))
(define-read-only (get-payment (lease-id uint) (period uint)) (map-get? rent-payments { lease-id: lease-id, period: period }))
(define-read-only (get-lease-count) (ok (var-get lease-count)))
(define-read-only (get-total-collected) (ok (var-get total-collected)))

Functions (7)

FunctionAccessArgs
create-leasepublictenant: principal, monthly-rent: uint, duration-months: uint
pay-rentpubliclease-id: uint
terminate-leasepubliclease-id: uint
get-leaseread-onlyid: uint
get-paymentread-onlylease-id: uint, period: uint
get-lease-countread-only
get-total-collectedread-only