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-already-retired (err u123))

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

(define-map carbon-credits
  uint
  {
    issuer: principal,
    project-id: (string-ascii 50),
    tonnes-co2: uint,
    vintage-year: uint,
    verification-standard: (string-ascii 30),
    location-hash: (buff 32),
    retired: bool,
    issued-block: uint
  }
)

(define-map credit-ownership
  {credit-id: uint, owner: principal}
  {
    amount: uint,
    acquired-block: uint
  }
)

(define-map credit-retirements
  {credit-id: uint, retirement-id: uint}
  {
    retiree: principal,
    amount: uint,
    beneficiary: (string-ascii 50),
    retirement-block: uint
  }
)

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

(define-map retirement-counter uint uint)
(define-map trade-counter uint uint)
(define-map issuer-credits principal (list 100 uint))
(define-map owner-credits principal (list 200 uint))

(define-public (issue-credits (project-id (string-ascii 50)) (tonnes uint) (vintage uint) 
                               (standard (string-ascii 30)) (location (buff 32)))
  (let
    (
      (credit-id (+ (var-get credit-nonce) u1))
    )
    (asserts! (> tonnes u0) err-invalid-amount)
    (map-set carbon-credits credit-id {
      issuer: tx-sender,
      project-id: project-id,
      tonnes-co2: tonnes,
      vintage-year: vintage,
      verification-standard: standard,
      location-hash: location,
      retired: false,
      issued-block: stacks-block-height
    })
    (map-set credit-ownership {credit-id: credit-id, owner: tx-sender} {
      amount: tonnes,
      acquired-block: stacks-block-height
    })
    (map-set retirement-counter credit-id u0)
    (map-set trade-counter credit-id u0)
    (map-set issuer-credits tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? issuer-credits tx-sender)) credit-id) u100)))
    (map-set owner-credits tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? owner-credits tx-sender)) credit-id) u200)))
    (var-set credit-nonce credit-id)
    (ok credit-id)
  )
)

(define-public (trade-credits (credit-id uint) (buyer principal) (amount uint) (price uint))
  (let
    (
      (credit (unwrap! (map-get? carbon-credits credit-id) err-not-found))
      (seller-ownership (unwrap! (map-get? credit-ownership {credit-id: credit-id, owner: tx-sender}) err-not-found))
      (buyer-ownership (default-to {amount: u0, acquired-block: stacks-block-height}
                        (map-get? credit-ownership {credit-id: credit-id, owner: buyer})))
      (trade-id (+ (default-to u0 (map-get? trade-counter credit-id)) u1))
    )
    (asserts! (not (get retired credit)) err-already-retired)
    (asserts! (>= (get amount seller-ownership) amount) err-invalid-amount)
    (try! (stx-transfer? price buyer tx-sender))
    (map-set credit-trades {credit-id: credit-id, trade-id: trade-id} {
      seller: tx-sender,
      buyer: buyer,
      amount: amount,
      price: price,
      block: stacks-block-height
    })
    (map-set trade-counter credit-id trade-id)
    (map-set credit-ownership {credit-id: credit-id, owner: tx-sender}
      (merge seller-ownership {amount: (- (get amount seller-ownership) amount)}))
    (map-set credit-ownership {credit-id: credit-id, owner: buyer}
      {amount: (+ (get amount buyer-ownership) amount), acquired-block: (get acquired-block buyer-ownership)})
    (map-set owner-credits buyer
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? owner-credits buyer)) credit-id) u200)))
    (ok trade-id)
  )
)

(define-public (retire-credits (credit-id uint) (amount uint) (beneficiary (string-ascii 50)))
  (let
    (
      (credit (unwrap! (map-get? carbon-credits credit-id) err-not-found))
      (ownership (unwrap! (map-get? credit-ownership {credit-id: credit-id, owner: tx-sender}) err-not-found))
      (retirement-id (+ (default-to u0 (map-get? retirement-counter credit-id)) u1))
    )
    (asserts! (not (get retired credit)) err-already-retired)
    (asserts! (>= (get amount ownership) amount) err-invalid-amount)
    (map-set credit-retirements {credit-id: credit-id, retirement-id: retirement-id} {
      retiree: tx-sender,
      amount: amount,
      beneficiary: beneficiary,
      retirement-block: stacks-block-height
    })
    (map-set retirement-counter credit-id retirement-id)
    (map-set credit-ownership {credit-id: credit-id, owner: tx-sender}
      (merge ownership {amount: (- (get amount ownership) amount)}))
    (ok retirement-id)
  )
)

(define-read-only (get-credit (credit-id uint))
  (ok (map-get? carbon-credits credit-id))
)

(define-read-only (get-ownership (credit-id uint) (owner principal))
  (ok (map-get? credit-ownership {credit-id: credit-id, owner: owner}))
)

(define-read-only (get-retirement (credit-id uint) (retirement-id uint))
  (ok (map-get? credit-retirements {credit-id: credit-id, retirement-id: retirement-id}))
)

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

(define-read-only (get-owner-credits (owner principal))
  (ok (map-get? owner-credits owner))
)

(define-read-only (calculate-total-retired (credit-id uint))
  u0
)

Functions (9)

FunctionAccessArgs
issue-creditspublicproject-id: (string-ascii 50
trade-creditspubliccredit-id: uint, buyer: principal, amount: uint, price: uint
retire-creditspubliccredit-id: uint, amount: uint, beneficiary: (string-ascii 50
get-creditread-onlycredit-id: uint
get-ownershipread-onlycredit-id: uint, owner: principal
get-retirementread-onlycredit-id: uint, retirement-id: uint
get-traderead-onlycredit-id: uint, trade-id: uint
get-owner-creditsread-onlyowner: principal
calculate-total-retiredread-onlycredit-id: uint