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-invalid-warrant (err u117))

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

(define-map venture-debts
  uint
  {
    startup: principal,
    lender: principal,
    principal-amount: uint,
    interest-rate: uint,
    warrant-coverage: uint,
    equity-kicker: uint,
    runway-months: uint,
    outstanding: uint,
    disbursed: bool,
    active: bool,
    issue-block: uint,
    maturity-block: uint
  }
)

(define-map warrants
  {debt-id: uint, warrant-id: uint}
  {
    holder: principal,
    strike-price: uint,
    shares: uint,
    exercised: bool,
    issue-block: uint
  }
)

(define-map warrant-counter uint uint)
(define-map startup-debts principal (list 20 uint))
(define-map lender-debts principal (list 50 uint))

(define-public (issue-venture-debt (lender principal) (amount uint) (rate uint) (warrant-cov uint) 
                                    (equity-kick uint) (runway uint) (maturity uint))
  (let
    (
      (debt-id (+ (var-get debt-nonce) u1))
    )
    (asserts! (> amount u0) err-invalid-amount)
    (asserts! (<= warrant-cov u30) err-invalid-warrant)
    (map-set venture-debts debt-id {
      startup: tx-sender,
      lender: lender,
      principal-amount: amount,
      interest-rate: rate,
      warrant-coverage: warrant-cov,
      equity-kicker: equity-kick,
      runway-months: runway,
      outstanding: amount,
      disbursed: false,
      active: false,
      issue-block: stacks-block-height,
      maturity-block: maturity
    })
    (map-set warrant-counter debt-id u0)
    (map-set startup-debts tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? startup-debts tx-sender)) debt-id) u20)))
    (map-set lender-debts lender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? lender-debts lender)) debt-id) u50)))
    (var-set debt-nonce debt-id)
    (ok debt-id)
  )
)

(define-public (disburse-funds (debt-id uint))
  (let
    (
      (debt (unwrap! (map-get? venture-debts debt-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get lender debt)) err-unauthorized)
    (asserts! (not (get disbursed debt)) err-invalid-amount)
    (try! (stx-transfer? (get principal-amount debt) tx-sender (get startup debt)))
    (map-set venture-debts debt-id (merge debt {disbursed: true, active: true}))
    (ok true)
  )
)

(define-public (issue-warrant (debt-id uint) (holder principal) (strike uint) (shares uint))
  (let
    (
      (debt (unwrap! (map-get? venture-debts debt-id) err-not-found))
      (warrant-id (+ (default-to u0 (map-get? warrant-counter debt-id)) u1))
    )
    (asserts! (is-eq tx-sender (get startup debt)) err-unauthorized)
    (map-set warrants {debt-id: debt-id, warrant-id: warrant-id} {
      holder: holder,
      strike-price: strike,
      shares: shares,
      exercised: false,
      issue-block: stacks-block-height
    })
    (map-set warrant-counter debt-id warrant-id)
    (ok warrant-id)
  )
)

(define-public (repay (debt-id uint) (amount uint))
  (let
    (
      (debt (unwrap! (map-get? venture-debts debt-id) err-not-found))
      (new-outstanding (if (>= amount (get outstanding debt)) u0 (- (get outstanding debt) amount)))
    )
    (asserts! (is-eq tx-sender (get startup debt)) err-unauthorized)
    (asserts! (get active debt) err-not-found)
    (try! (stx-transfer? amount tx-sender (get lender debt)))
    (map-set venture-debts debt-id (merge debt {
      outstanding: new-outstanding,
      active: (> new-outstanding u0)
    }))
    (ok true)
  )
)

(define-public (exercise-warrant (debt-id uint) (warrant-id uint) (payment uint))
  (let
    (
      (warrant (unwrap! (map-get? warrants {debt-id: debt-id, warrant-id: warrant-id}) err-not-found))
      (debt (unwrap! (map-get? venture-debts debt-id) err-not-found))
      (required (/ (* (get strike-price warrant) (get shares warrant)) u100))
    )
    (asserts! (is-eq tx-sender (get holder warrant)) err-unauthorized)
    (asserts! (not (get exercised warrant)) err-invalid-warrant)
    (asserts! (>= payment required) err-invalid-amount)
    (try! (stx-transfer? required tx-sender (get startup debt)))
    (map-set warrants {debt-id: debt-id, warrant-id: warrant-id} (merge warrant {exercised: true}))
    (ok true)
  )
)

(define-read-only (get-debt (debt-id uint))
  (ok (map-get? venture-debts debt-id))
)

(define-read-only (get-warrant (debt-id uint) (warrant-id uint))
  (ok (map-get? warrants {debt-id: debt-id, warrant-id: warrant-id}))
)

(define-read-only (get-startup-debts (startup principal))
  (ok (map-get? startup-debts startup))
)

(define-read-only (calculate-total-due (debt-id uint))
  (let
    (
      (debt (unwrap-panic (map-get? venture-debts debt-id)))
      (outstanding (get outstanding debt))
      (rate (get interest-rate debt))
      (elapsed (- stacks-block-height (get issue-block debt)))
    )
    (+ outstanding (/ (* outstanding (* rate elapsed)) u10000000))
  )
)

(define-read-only (get-warrant-value (debt-id uint) (warrant-id uint) (current-price uint))
  (let
    (
      (warrant (unwrap-panic (map-get? warrants {debt-id: debt-id, warrant-id: warrant-id})))
      (strike (get strike-price warrant))
      (shares (get shares warrant))
    )
    (if (> current-price strike)
      (ok (/ (* (- current-price strike) shares) u100))
      (ok u0)
    )
  )
)

Functions (10)

FunctionAccessArgs
issue-venture-debtpubliclender: principal, amount: uint, rate: uint, warrant-cov: uint, equity-kick: uint, runway: uint, maturity: uint
disburse-fundspublicdebt-id: uint
issue-warrantpublicdebt-id: uint, holder: principal, strike: uint, shares: uint
repaypublicdebt-id: uint, amount: uint
exercise-warrantpublicdebt-id: uint, warrant-id: uint, payment: uint
get-debtread-onlydebt-id: uint
get-warrantread-onlydebt-id: uint, warrant-id: uint
get-startup-debtsread-onlystartup: principal
calculate-total-dueread-onlydebt-id: uint
get-warrant-valueread-onlydebt-id: uint, warrant-id: uint, current-price: uint