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-data-var lbo-nonce uint u0)

(define-map lbo-models
  uint
  {
    sponsor: principal,
    target-company: principal,
    purchase-price: uint,
    equity-contribution: uint,
    debt-financing: uint,
    leverage-ratio: uint,
    debt-interest-rate: uint,
    exit-multiple: uint,
    hold-period-blocks: uint,
    created-block: uint,
    exited: bool
  }
)

(define-map debt-schedules
  {lbo-id: uint, period: uint}
  {
    beginning-balance: uint,
    interest-expense: uint,
    principal-payment: uint,
    ending-balance: uint
  }
)

(define-map lbo-returns
  uint
  {
    exit-value: uint,
    debt-paydown: uint,
    equity-proceeds: uint,
    irr: uint,
    moic: uint
  }
)

(define-map sponsor-lbos principal (list 30 uint))

(define-public (create-lbo (target principal) (price uint) (equity uint) (debt uint) 
                            (leverage uint) (rate uint) (exit-mult uint) (hold-period uint))
  (let
    (
      (lbo-id (+ (var-get lbo-nonce) u1))
    )
    (asserts! (is-eq (+ equity debt) price) err-invalid-amount)
    (map-set lbo-models lbo-id {
      sponsor: tx-sender,
      target-company: target,
      purchase-price: price,
      equity-contribution: equity,
      debt-financing: debt,
      leverage-ratio: leverage,
      debt-interest-rate: rate,
      exit-multiple: exit-mult,
      hold-period-blocks: hold-period,
      created-block: stacks-block-height,
      exited: false
    })
    (map-set sponsor-lbos tx-sender
      (unwrap-panic (as-max-len? (append (default-to (list) (map-get? sponsor-lbos tx-sender)) lbo-id) u30)))
    (var-set lbo-nonce lbo-id)
    (ok lbo-id)
  )
)

(define-public (add-debt-schedule (lbo-id uint) (period uint) (beginning uint) 
                                   (interest uint) (principal uint))
  (let
    (
      (lbo (unwrap! (map-get? lbo-models lbo-id) err-not-found))
      (ending (- beginning principal))
    )
    (asserts! (is-eq tx-sender (get sponsor lbo)) err-unauthorized)
    (map-set debt-schedules {lbo-id: lbo-id, period: period} {
      beginning-balance: beginning,
      interest-expense: interest,
      principal-payment: principal,
      ending-balance: ending
    })
    (ok ending)
  )
)

(define-public (execute-exit (lbo-id uint) (exit-value uint))
  (let
    (
      (lbo (unwrap! (map-get? lbo-models lbo-id) err-not-found))
      (remaining-debt (calculate-remaining-debt lbo-id))
      (equity-proceeds (- exit-value remaining-debt))
      (moic (/ (* equity-proceeds u100) (get equity-contribution lbo)))
    )
    (asserts! (is-eq tx-sender (get sponsor lbo)) err-unauthorized)
    (asserts! (not (get exited lbo)) err-not-found)
    (map-set lbo-returns lbo-id {
      exit-value: exit-value,
      debt-paydown: remaining-debt,
      equity-proceeds: equity-proceeds,
      irr: u0,
      moic: moic
    })
    (map-set lbo-models lbo-id (merge lbo {exited: true}))
    (ok equity-proceeds)
  )
)

(define-public (update-irr (lbo-id uint) (calculated-irr uint))
  (let
    (
      (lbo (unwrap! (map-get? lbo-models lbo-id) err-not-found))
      (returns (unwrap! (map-get? lbo-returns lbo-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get sponsor lbo)) err-unauthorized)
    (map-set lbo-returns lbo-id (merge returns {irr: calculated-irr}))
    (ok calculated-irr)
  )
)

(define-read-only (get-lbo (lbo-id uint))
  (ok (map-get? lbo-models lbo-id))
)

(define-read-only (get-debt-schedule (lbo-id uint) (period uint))
  (ok (map-get? debt-schedules {lbo-id: lbo-id, period: period}))
)

(define-read-only (get-returns (lbo-id uint))
  (ok (map-get? lbo-returns lbo-id))
)

(define-read-only (get-sponsor-lbos (sponsor principal))
  (ok (map-get? sponsor-lbos sponsor))
)

(define-read-only (calculate-remaining-debt (lbo-id uint))
  (let
    (
      (lbo (unwrap-panic (map-get? lbo-models lbo-id)))
      (initial-debt (get debt-financing lbo))
    )
    initial-debt
  )
)

(define-read-only (calculate-exit-value (lbo-id uint) (ebitda uint))
  (let
    (
      (lbo (unwrap-panic (map-get? lbo-models lbo-id)))
      (multiple (get exit-multiple lbo))
    )
    (/ (* ebitda multiple) u100)
  )
)

(define-read-only (calculate-leverage-ratio (lbo-id uint))
  (let
    (
      (lbo (unwrap-panic (map-get? lbo-models lbo-id)))
    )
    (ok (/ (* (get debt-financing lbo) u100) (get purchase-price lbo)))
  )
)

(define-read-only (get-lbo-metrics (lbo-id uint))
  (let
    (
      (lbo (unwrap-panic (map-get? lbo-models lbo-id)))
      (returns-data (map-get? lbo-returns lbo-id))
    )
    (ok {
      purchase-price: (get purchase-price lbo),
      equity-contribution: (get equity-contribution lbo),
      leverage-ratio: (get leverage-ratio lbo),
      exited: (get exited lbo)
    })
  )
)

Functions (12)

FunctionAccessArgs
create-lbopublictarget: principal, price: uint, equity: uint, debt: uint, leverage: uint, rate: uint, exit-mult: uint, hold-period: uint
add-debt-schedulepubliclbo-id: uint, period: uint, beginning: uint, interest: uint, principal: uint
execute-exitpubliclbo-id: uint, exit-value: uint
update-irrpubliclbo-id: uint, calculated-irr: uint
get-lboread-onlylbo-id: uint
get-debt-scheduleread-onlylbo-id: uint, period: uint
get-returnsread-onlylbo-id: uint
get-sponsor-lbosread-onlysponsor: principal
calculate-remaining-debtread-onlylbo-id: uint
calculate-exit-valueread-onlylbo-id: uint, ebitda: uint
calculate-leverage-ratioread-onlylbo-id: uint
get-lbo-metricsread-onlylbo-id: uint