Source Code

;; Central Data Store for Real Estate Investment
;; This contract stores ALL shared data that multiple contracts need to access.
;; All other contracts can READ from this, and authorized contracts can WRITE to it.

(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_NOT_AUTHORIZED (err u1001))
(define-constant ERR_INVALID_INPUT (err u1002))
(define-constant ERR_ARITHMETIC_OVERFLOW (err u1003))

;; CONSTANTS FOR VALIDATION
(define-constant MAX_SBTC_AMOUNT u1000000000000)
(define-constant MAX_PROPERTY_COUNT u1000)
(define-constant MAX_INVESTOR_COUNT u1000)
(define-constant MAX_BLOCK_HEIGHT u340282366920938463463374607431768211455)

;; Authorization now uses contract-caller properly
;; This private function is used for documentation purposes only
;; The actual check is done inline in public functions using contract-caller
(define-read-only (is-authorized-caller)
  (or (is-eq contract-caller .property-registry-v3)
      (is-eq contract-caller .investment-manager-v3)
      (is-eq contract-caller .rental-distributor-v3)))

;; VALIDATION HELPERS
(define-private (is-valid-sbtc-amount (amount uint))
  (and (>= amount u0) (<= amount MAX_SBTC_AMOUNT)))

(define-private (is-valid-block-height (height uint))
  (and (>= height u0) (<= height MAX_BLOCK_HEIGHT)))

(define-private (is-valid-count (count uint))
  (and (>= count u0) (<= count MAX_INVESTOR_COUNT)))

(define-private (is-valid-property-count (count uint))
  (and (>= count u0) (<= count MAX_PROPERTY_COUNT)))

;; Safe arithmetic operations
(define-private (safe-add (a uint) (b uint))
  (let ((result (+ a b)))
    (if (and (>= result a) (>= result b))
      (ok result)
      ERR_ARITHMETIC_OVERFLOW)))

(define-private (safe-sub (a uint) (b uint))
  (if (>= a b)
    (ok (- a b))
    ERR_ARITHMETIC_OVERFLOW))

(define-private (safe-mul (a uint) (b uint))
  (if (is-eq b u0)
    (ok u0)
    (let ((result (* a b)))
      (if (is-eq (/ result b) a)
        (ok result)
        ERR_ARITHMETIC_OVERFLOW))))

;; INVESTMENT DATA STORAGE
(define-map user-property-investments
  { property-id: uint, investor: principal }
  { 
    sbtc-invested: uint,
    investment-date: uint,
    last-updated: uint
  })

(define-map property-investment-totals
  { property-id: uint }
  { 
    total-sbtc-invested: uint,
    investor-count: uint,
    last-updated: uint
  })

(define-map user-portfolio-totals
  { investor: principal }
  { 
    total-sbtc-invested: uint,
    property-count: uint,
    total-earnings: uint,
    last-updated: uint
  })

;; READ FUNCTIONS (anyone can read)
(define-read-only (get-user-investment (property-id uint) (investor principal))
  (default-to 
    { sbtc-invested: u0, investment-date: u0, last-updated: u0 }
    (map-get? user-property-investments { property-id: property-id, investor: investor })))

(define-read-only (get-property-investment-totals (property-id uint))
  (default-to 
    { total-sbtc-invested: u0, investor-count: u0, last-updated: u0 }
    (map-get? property-investment-totals { property-id: property-id })))

(define-read-only (get-user-portfolio (investor principal))
  (default-to 
    { total-sbtc-invested: u0, property-count: u0, total-earnings: u0, last-updated: u0 }
    (map-get? user-portfolio-totals { investor: investor })))

;; WRITE FUNCTIONS (only authorized contracts)
;; All authorization checks now use contract-caller directly
(define-public (update-user-investment 
    (property-id uint) 
    (investor principal) 
    (sbtc-invested uint)
    (investment-date uint))
  (begin
    ;; Authorization check uses contract-caller inline
    (asserts! (or (is-eq contract-caller .property-registry-v3)
                  (is-eq contract-caller .investment-manager-v3)
                  (is-eq contract-caller .rental-distributor-v3))
              ERR_NOT_AUTHORIZED)
    
    ;; Input validation
    (asserts! (> property-id u0) ERR_INVALID_INPUT)
    (asserts! (is-standard investor) ERR_INVALID_INPUT)
    (asserts! (is-valid-sbtc-amount sbtc-invested) ERR_INVALID_INPUT)
    (asserts! (is-valid-block-height investment-date) ERR_INVALID_INPUT)
    (asserts! (<= investment-date stacks-block-height) ERR_INVALID_INPUT)
    
    (map-set user-property-investments
      { property-id: property-id, investor: investor }
      { 
        sbtc-invested: sbtc-invested,
        investment-date: investment-date,
        last-updated: stacks-block-height
      })
    (ok true)))

(define-public (update-property-totals
    (property-id uint)
    (total-sbtc-invested uint)
    (investor-count uint))
  (begin
    ;; Authorization check uses contract-caller inline
    (asserts! (or (is-eq contract-caller .property-registry-v3)
                  (is-eq contract-caller .investment-manager-v3)
                  (is-eq contract-caller .rental-distributor-v3))
              ERR_NOT_AUTHORIZED)
    
    ;; Input validation
    (asserts! (> property-id u0) ERR_INVALID_INPUT)
    (asserts! (is-valid-sbtc-amount total-sbtc-invested) ERR_INVALID_INPUT)
    (asserts! (is-valid-count investor-count) ERR_INVALID_INPUT)
    
    (map-set property-investment-totals
      { property-id: property-id }
      {
        total-sbtc-invested: total-sbtc-invested,
        investor-count: investor-count,
        last-updated: stacks-block-height
      })
    (ok true)))

(define-public (update-user-portfolio
    (investor principal)
    (total-sbtc-invested uint)
    (property-count uint)
    (total-earnings uint))
  (begin
    ;; Authorization check uses contract-caller inline
    (asserts! (or (is-eq contract-caller .property-registry-v3)
                  (is-eq contract-caller .investment-manager-v3)
                  (is-eq contract-caller .rental-distributor-v3))
              ERR_NOT_AUTHORIZED)
    
    ;; Input validation
    (asserts! (is-standard investor) ERR_INVALID_INPUT)
    (asserts! (is-valid-sbtc-amount total-sbtc-invested) ERR_INVALID_INPUT)
    (asserts! (is-valid-property-count property-count) ERR_INVALID_INPUT)
    (asserts! (is-valid-sbtc-amount total-earnings) ERR_INVALID_INPUT)
    
    (map-set user-portfolio-totals
      { investor: investor }
      {
        total-sbtc-invested: total-sbtc-invested,
        property-count: property-count,
        total-earnings: total-earnings,
        last-updated: stacks-block-height
      })
    (ok true)))

;; EMERGENCY READ-ONLY FUNCTIONS (for debugging/monitoring)
(define-read-only (get-total-properties-tracked)
  u0)

(define-read-only (verify-caller (expected-caller principal))
  ;; Utility function for testing authorization
  (ok (is-eq contract-caller expected-caller)))

Functions (16)

FunctionAccessArgs
is-authorized-callerread-only
is-valid-sbtc-amountprivateamount: uint
is-valid-block-heightprivateheight: uint
is-valid-countprivatecount: uint
is-valid-property-countprivatecount: uint
safe-addprivatea: uint, b: uint
safe-subprivatea: uint, b: uint
safe-mulprivatea: uint, b: uint
get-user-investmentread-onlyproperty-id: uint, investor: principal
get-property-investment-totalsread-onlyproperty-id: uint
get-user-portfolioread-onlyinvestor: principal
update-user-investmentpublicproperty-id: uint, investor: principal, sbtc-invested: uint, investment-date: uint
update-property-totalspublicproperty-id: uint, total-sbtc-invested: uint, investor-count: uint
update-user-portfoliopublicinvestor: principal, total-sbtc-invested: uint, property-count: uint, total-earnings: uint
get-total-properties-trackedread-only
verify-callerread-onlyexpected-caller: principal