Source Code

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-unauthorized (err u102))
(define-constant err-invalid-amount (err u104))
(define-constant err-offline (err u119))

(define-data-var plant-nonce uint u0)

(define-map virtual-plants
  uint
  {
    operator: principal,
    total-capacity: uint,
    available-capacity: uint,
    energy-price: uint,
    location-hash: (buff 32),
    active: bool,
    uptime-percentage: uint,
    created-block: uint
  }
)

(define-map energy-devices
  {plant-id: uint, device-id: uint}
  {
    owner: principal,
    capacity: uint,
    device-type: (string-ascii 20),
    contribution: uint,
    rewards-earned: uint,
    online: bool
  }
)

(define-map energy-trades
  {plant-id: uint, trade-id: uint}
  {
    buyer: principal,
    amount: uint,
    price: uint,
    block: uint
  }
)

(define-map device-counter uint uint)
(define-map trade-counter uint uint)
(define-map operator-plants principal (list 20 uint))

(define-public (create-vpp (capacity uint) (price uint) (location (buff 32)))
  (let
    (
      (plant-id (+ (var-get plant-nonce) u1))
    )
    (asserts! (> capacity u0) err-invalid-amount)
    (map-set virtual-plants plant-id {
      operator: tx-sender,
      total-capacity: capacity,
      available-capacity: capacity,
      energy-price: price,
      location-hash: location,
      active: true,
      uptime-percentage: u100,
      created-block: stacks-block-height
    })
    (map-set device-counter plant-id u0)
    (map-set trade-counter plant-id u0)
    (map-set operator-plants tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? operator-plants tx-sender)) plant-id) u20)))
    (var-set plant-nonce plant-id)
    (ok plant-id)
  )
)

(define-public (register-device (plant-id uint) (capacity uint) (device-type (string-ascii 20)))
  (let
    (
      (plant (unwrap! (map-get? virtual-plants plant-id) err-not-found))
      (device-id (+ (default-to u0 (map-get? device-counter plant-id)) u1))
      (new-capacity (+ (get total-capacity plant) capacity))
    )
    (map-set energy-devices {plant-id: plant-id, device-id: device-id} {
      owner: tx-sender,
      capacity: capacity,
      device-type: device-type,
      contribution: u0,
      rewards-earned: u0,
      online: true
    })
    (map-set device-counter plant-id device-id)
    (map-set virtual-plants plant-id (merge plant {
      total-capacity: new-capacity,
      available-capacity: (+ (get available-capacity plant) capacity)
    }))
    (ok device-id)
  )
)

(define-public (purchase-energy (plant-id uint) (amount uint))
  (let
    (
      (plant (unwrap! (map-get? virtual-plants plant-id) err-not-found))
      (cost (* amount (get energy-price plant)))
      (trade-id (+ (default-to u0 (map-get? trade-counter plant-id)) u1))
    )
    (asserts! (get active plant) err-offline)
    (asserts! (<= amount (get available-capacity plant)) err-invalid-amount)
    (try! (stx-transfer? cost tx-sender (get operator plant)))
    (map-set energy-trades {plant-id: plant-id, trade-id: trade-id} {
      buyer: tx-sender,
      amount: amount,
      price: (get energy-price plant),
      block: stacks-block-height
    })
    (map-set trade-counter plant-id trade-id)
    (map-set virtual-plants plant-id (merge plant {
      available-capacity: (- (get available-capacity plant) amount)
    }))
    (ok trade-id)
  )
)

(define-public (update-device-contribution (plant-id uint) (device-id uint) (contribution uint))
  (let
    (
      (plant (unwrap! (map-get? virtual-plants plant-id) err-not-found))
      (device (unwrap! (map-get? energy-devices {plant-id: plant-id, device-id: device-id}) err-not-found))
    )
    (asserts! (is-eq tx-sender (get operator plant)) err-unauthorized)
    (map-set energy-devices {plant-id: plant-id, device-id: device-id}
      (merge device {contribution: (+ (get contribution device) contribution)}))
    (ok true)
  )
)

(define-read-only (get-plant (plant-id uint))
  (ok (map-get? virtual-plants plant-id))
)

(define-read-only (get-device (plant-id uint) (device-id uint))
  (ok (map-get? energy-devices {plant-id: plant-id, device-id: device-id}))
)

(define-read-only (get-trade (plant-id uint) (trade-id uint))
  (ok (map-get? energy-trades {plant-id: plant-id, trade-id: trade-id}))
)

(define-read-only (get-operator-plants (operator principal))
  (ok (map-get? operator-plants operator))
)

(define-read-only (calculate-capacity-utilization (plant-id uint))
  (let
    (
      (plant (unwrap-panic (map-get? virtual-plants plant-id)))
      (total (get total-capacity plant))
      (available (get available-capacity plant))
    )
    (if (> total u0)
      (ok (/ (* (- total available) u100) total))
      (ok u0)
    )
  )
)

Functions (9)

FunctionAccessArgs
create-vpppubliccapacity: uint, price: uint, location: (buff 32
register-devicepublicplant-id: uint, capacity: uint, device-type: (string-ascii 20
purchase-energypublicplant-id: uint, amount: uint
update-device-contributionpublicplant-id: uint, device-id: uint, contribution: uint
get-plantread-onlyplant-id: uint
get-deviceread-onlyplant-id: uint, device-id: uint
get-traderead-onlyplant-id: uint, trade-id: uint
get-operator-plantsread-onlyoperator: principal
calculate-capacity-utilizationread-onlyplant-id: uint