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-not-distressed (err u114))
(define-constant err-already-acquired (err u115))

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

(define-map distressed-assets
  uint
  {
    original-debtor: principal,
    current-owner: principal,
    face-value: uint,
    discount-rate: uint,
    acquisition-price: uint,
    recovery-amount: uint,
    distress-type: (string-ascii 30),
    acquired: bool,
    resolved: bool,
    list-block: uint
  }
)

(define-map bids
  {asset-id: uint, bidder: principal}
  {
    bid-amount: uint,
    bid-block: uint,
    accepted: bool
  }
)

(define-map asset-bidders uint (list 50 principal))
(define-map owner-assets principal (list 50 uint))

(define-public (list-distressed-asset (face-value uint) (discount uint) (distress-type (string-ascii 30)))
  (let
    (
      (asset-id (+ (var-get asset-nonce) u1))
    )
    (asserts! (> face-value u0) err-invalid-amount)
    (asserts! (<= discount u100) err-invalid-amount)
    (map-set distressed-assets asset-id {
      original-debtor: tx-sender,
      current-owner: tx-sender,
      face-value: face-value,
      discount-rate: discount,
      acquisition-price: u0,
      recovery-amount: u0,
      distress-type: distress-type,
      acquired: false,
      resolved: false,
      list-block: stacks-block-height
    })
    (map-set owner-assets tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? owner-assets tx-sender)) asset-id) u50)))
    (var-set asset-nonce asset-id)
    (ok asset-id)
  )
)

(define-public (place-bid (asset-id uint) (amount uint))
  (let
    (
      (asset (unwrap! (map-get? distressed-assets asset-id) err-not-found))
    )
    (asserts! (not (get acquired asset)) err-already-acquired)
    (asserts! (> amount u0) err-invalid-amount)
    (map-set bids {asset-id: asset-id, bidder: tx-sender} {
      bid-amount: amount,
      bid-block: stacks-block-height,
      accepted: false
    })
    (map-set asset-bidders asset-id
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? asset-bidders asset-id)) tx-sender) u50)))
    (ok true)
  )
)

(define-public (accept-bid (asset-id uint) (bidder principal))
  (let
    (
      (asset (unwrap! (map-get? distressed-assets asset-id) err-not-found))
      (bid (unwrap! (map-get? bids {asset-id: asset-id, bidder: bidder}) err-not-found))
    )
    (asserts! (is-eq tx-sender (get current-owner asset)) err-unauthorized)
    (asserts! (not (get acquired asset)) err-already-acquired)
    (try! (stx-transfer? (get bid-amount bid) bidder tx-sender))
    (map-set bids {asset-id: asset-id, bidder: bidder} (merge bid {accepted: true}))
    (map-set distressed-assets asset-id (merge asset {
      current-owner: bidder,
      acquisition-price: (get bid-amount bid),
      acquired: true
    }))
    (map-set owner-assets bidder
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? owner-assets bidder)) asset-id) u50)))
    (ok true)
  )
)

(define-public (record-recovery (asset-id uint) (amount uint))
  (let
    (
      (asset (unwrap! (map-get? distressed-assets asset-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get current-owner asset)) err-unauthorized)
    (asserts! (get acquired asset) err-not-distressed)
    (map-set distressed-assets asset-id (merge asset {
      recovery-amount: (+ (get recovery-amount asset) amount),
      resolved: (>= (+ (get recovery-amount asset) amount) (get acquisition-price asset))
    }))
    (ok true)
  )
)

(define-read-only (get-asset (asset-id uint))
  (ok (map-get? distressed-assets asset-id))
)

(define-read-only (get-bid (asset-id uint) (bidder principal))
  (ok (map-get? bids {asset-id: asset-id, bidder: bidder}))
)

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

(define-read-only (calculate-discount-price (asset-id uint))
  (let
    (
      (asset (unwrap-panic (map-get? distressed-assets asset-id)))
      (face (get face-value asset))
      (discount (get discount-rate asset))
    )
    (- face (/ (* face discount) u100))
  )
)

(define-read-only (get-recovery-rate (asset-id uint))
  (let
    (
      (asset (unwrap-panic (map-get? distressed-assets asset-id)))
    )
    (if (> (get acquisition-price asset) u0)
      (ok (/ (* (get recovery-amount asset) u100) (get acquisition-price asset)))
      (ok u0)
    )
  )
)

Functions (9)

FunctionAccessArgs
list-distressed-assetpublicface-value: uint, discount: uint, distress-type: (string-ascii 30
place-bidpublicasset-id: uint, amount: uint
accept-bidpublicasset-id: uint, bidder: principal
record-recoverypublicasset-id: uint, amount: uint
get-assetread-onlyasset-id: uint
get-bidread-onlyasset-id: uint, bidder: principal
get-owner-assetsread-onlyowner: principal
calculate-discount-priceread-onlyasset-id: uint
get-recovery-rateread-onlyasset-id: uint