Source Code

;; Debt Consolidation Contract
;; Consolidates multiple debts into a single loan

(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_UNAUTHORIZED (err u401))
(define-constant ERR_INVALID_AMOUNT (err u402))
(define-constant ERR_INSUFFICIENT_FUNDS (err u403))
(define-constant ERR_LOAN_NOT_FOUND (err u404))
(define-constant ERR_ALREADY_CONSOLIDATED (err u405))

;; Data structures
(define-map consolidation-loans
    { loan-id: uint }
    {
        borrower: principal,
        total-debt: uint,
        new-rate: uint,
        monthly-payment: uint,
        term-months: uint,
        start-block: uint,
        active: bool,
        debts-consolidated: (list 10 uint)
    }
)

(define-map original-debts
    { debt-id: uint }
    {
        creditor: principal,
        amount: uint,
        rate: uint,
        consolidated: bool
    }
)

(define-data-var next-loan-id uint u1)
(define-data-var next-debt-id uint u1)
(define-data-var total-pool uint u0)

;; Add debt to be consolidated
(define-public (add-debt (creditor principal) (amount uint) (rate uint))
    (let (
        (debt-id (var-get next-debt-id))
    )
        (map-set original-debts
            { debt-id: debt-id }
            {
                creditor: creditor,
                amount: amount,
                rate: rate,
                consolidated: false
            }
        )
        (var-set next-debt-id (+ debt-id u1))
        (ok debt-id)
    )
)

;; Create consolidation loan
(define-public (consolidate-debts (debt-ids (list 10 uint)) (new-rate uint) (term-months uint))
    (let (
        (loan-id (var-get next-loan-id))
        (total-debt (calculate-total-debt debt-ids))
        (monthly-payment (calculate-monthly-payment total-debt new-rate term-months))
    )
        (asserts! (> total-debt u0) ERR_INVALID_AMOUNT)
        
        ;; Pay off original debts
        (try! (pay-off-debts debt-ids))
        
        ;; Create new consolidated loan
        (map-set consolidation-loans
            { loan-id: loan-id }
            {
                borrower: tx-sender,
                total-debt: total-debt,
                new-rate: new-rate,
                monthly-payment: monthly-payment,
                term-months: term-months,
                start-block: block-height,
                active: true,
                debts-consolidated: debt-ids
            }
        )
        
        ;; Mark debts as consolidated
        (try! (mark-debts-consolidated debt-ids))
        
        (var-set next-loan-id (+ loan-id u1))
        (ok loan-id)
    )
)

;; Make payment on consolidated loan
(define-public (make-payment (loan-id uint) (amount uint))
    (let (
        (loan (unwrap! (map-get? consolidation-loans { loan-id: loan-id }) ERR_LOAN_NOT_FOUND))
    )
        (asserts! (is-eq (get borrower loan) tx-sender) ERR_UNAUTHORIZED)
        (asserts! (get active loan) ERR_LOAN_NOT_FOUND)
        
        (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
        
        ;; Update loan balance
        (let (
            (new-balance (- (get total-debt loan) amount))
        )
            (if (<= new-balance u0)
                (map-set consolidation-loans { loan-id: loan-id } (merge loan { active: false, total-debt: u0 }))
                (map-set consolidation-loans { loan-id: loan-id } (merge loan { total-debt: new-balance }))
            )
        )
        (ok true)
    )
)

;; Calculate total debt from debt IDs
(define-private (calculate-total-debt (debt-ids (list 10 uint)))
    (fold + (map get-debt-amount debt-ids) u0)
)

(define-private (get-debt-amount (debt-id uint))
    (match (map-get? original-debts { debt-id: debt-id })
        debt (get amount debt)
        u0
    )
)

;; Pay off original debts
(define-private (pay-off-debts (debt-ids (list 10 uint)))
    (fold pay-off-single-debt debt-ids (ok true))
)

(define-private (pay-off-single-debt (debt-id uint) (prev-result (response bool uint)))
    (match prev-result
        success (let (
            (debt (unwrap! (map-get? original-debts { debt-id: debt-id }) ERR_LOAN_NOT_FOUND))
        )
            (try! (as-contract (stx-transfer? (get amount debt) tx-sender (get creditor debt))))
            (ok true)
        )
        error (err error)
    )
)

;; Mark debts as consolidated
(define-private (mark-debts-consolidated (debt-ids (list 10 uint)))
    (fold mark-single-debt-consolidated debt-ids (ok true))
)

(define-private (mark-single-debt-consolidated (debt-id uint) (prev-result (response bool uint)))
    (match prev-result
        success (let (
            (debt (unwrap! (map-get? original-debts { debt-id: debt-id }) ERR_LOAN_NOT_FOUND))
        )
            (map-set original-debts { debt-id: debt-id } (merge debt { consolidated: true }))
            (ok true)
        )
        error (err error)
    )
)

;; Calculate monthly payment
(define-private (calculate-monthly-payment (principal uint) (annual-rate uint) (term-months uint))
    (let (
        (monthly-rate (/ annual-rate u1200)) ;; annual rate / 12 / 100
        (payment-factor (/ (* monthly-rate (pow (+ u100 monthly-rate) term-months)) 
                          (- (pow (+ u100 monthly-rate) term-months) u100)))
    )
        (/ (* principal payment-factor) u100)
    )
)

;; Read-only functions
(define-read-only (get-consolidation-loan (loan-id uint))
    (map-get? consolidation-loans { loan-id: loan-id })
)

(define-read-only (get-debt (debt-id uint))
    (map-get? original-debts { debt-id: debt-id })
)

(define-read-only (calculate-savings (debt-ids (list 10 uint)) (new-rate uint) (term-months uint))
    (let (
        (total-debt (calculate-total-debt debt-ids))
        (old-payments (calculate-old-total-payments debt-ids))
        (new-payment (calculate-monthly-payment total-debt new-rate term-months))
        (new-total (* new-payment term-months))
    )
        (if (> old-payments new-total)
            (- old-payments new-total)
            u0
        )
    )
)

(define-private (calculate-old-total-payments (debt-ids (list 10 uint)))
    (fold + (map calculate-old-payment debt-ids) u0)
)

(define-private (calculate-old-payment (debt-id uint))
    (match (map-get? original-debts { debt-id: debt-id })
        debt (* (get amount debt) (+ u100 (get rate debt)) u12) ;; simplified calculation
        u0
    )
)

Functions (15)

FunctionAccessArgs
add-debtpubliccreditor: principal, amount: uint, rate: uint
consolidate-debtspublicdebt-ids: (list 10 uint
make-paymentpublicloan-id: uint, amount: uint
calculate-total-debtprivatedebt-ids: (list 10 uint
get-debt-amountprivatedebt-id: uint
pay-off-debtsprivatedebt-ids: (list 10 uint
pay-off-single-debtprivatedebt-id: uint, prev-result: (response bool uint
mark-debts-consolidatedprivatedebt-ids: (list 10 uint
mark-single-debt-consolidatedprivatedebt-id: uint, prev-result: (response bool uint
calculate-monthly-paymentprivateprincipal: uint, annual-rate: uint, term-months: uint
get-consolidation-loanread-onlyloan-id: uint
get-debtread-onlydebt-id: uint
calculate-savingsread-onlydebt-ids: (list 10 uint
calculate-old-total-paymentsprivatedebt-ids: (list 10 uint
calculate-old-paymentprivatedebt-id: uint