;; Define the contract's data variables
;; Maps a user's principal address to their deposited amount.
(define-map deposits
{ owner: principal }
{ amount: uint }
)
;; Maps a borrower's principal address to their loan details: amount and the last interaction block.
(define-map loans
principal
{
amount: uint,
last-interaction-block: uint,
}
)
;; Holds the total amount of deposits in the contract, initialized to 0.
(define-data-var total-deposits uint u0)
;; Represents the reserve funds in the pool, initialized to 0.
(define-data-var pool-reserve uint u0)
;; The interest rate for loans, represented as 10% (out of a base of 100).
(define-data-var loan-interest-rate uint u10) ;; Representing 10% interest rate
;; Error constants for various failure scenarios.
(define-constant err-no-interest (err u100))
(define-constant err-overpay (err u200))
(define-constant err-overborrow (err u300))
;; Public function for users to deposit STX into the contract.
;; Updates their balance and the total deposits in the contract.
(define-public (deposit (amount uint))
(let (
;; Fetch the current balance or default to 0 if none exists.
(current-balance (default-to u0 (get amount (map-get? deposits { owner: tx-sender }))))
)
;; Transfer the STX from sender = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" to recipient = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stx-defi (ie: contract identifier on the chain!)".
(try! (stx-transfer? amount tx-sender current-contract))
;; Update the user's deposit amount in the map.
(map-set deposits { owner: tx-sender } { amount: (+ current-balance amount) })
;; Update the total deposits variable.
(var-set total-deposits (+ (var-get total-deposits) amount))
;; Return success.
(ok true)
)
)
;; Public function for users to borrow STX based on their deposits.
(define-public (borrow (amount uint))
(let (
;; Fetch user's deposit or default to 0.
(user-deposit (default-to u0 (get amount (map-get? deposits { owner: tx-sender }))))
;; Calculate the maximum amount the user is allowed to borrow. (which will be upto HALF of what they deposited)
(allowed-borrow (/ user-deposit u2))
;; Fetch current loan details or default to initial values.
(current-loan-details (default-to {
amount: u0,
last-interaction-block: u0,
}
(map-get? loans tx-sender)
))
;; Calculate accrued interest on the current loan.
(accrued-interest (calculate-accrued-interest (get amount current-loan-details)
(get last-interaction-block current-loan-details)
))
;; Calculate the total amount due including interest.
(total-due (+ (get amount current-loan-details) (unwrap-panic accrued-interest)))
;; Calculate the new loan total after borrowing additional amount.
(new-loan (+ amount))
)
;; Ensure the requested borrow amount does not exceed the allowed amount.
(asserts! (<= new-loan allowed-borrow) err-overborrow)
;; Transfer the borrowed STX to the user.
(let ((recipient tx-sender))
(try! (as-contract? ((with-stx amount))
(try! (stx-transfer? amount current-contract recipient))
))
)
;; Update the user's loan details in the map.
(map-set loans tx-sender {
amount: new-loan,
last-interaction-block: burn-block-height,
})
;; Return success.
(ok true)
)
)
;; Read-only function to get the total balance by tx-sender
(define-read-only (get-balance-by-sender)
(ok (map-get? deposits { owner: tx-sender }))
)
;; Read-only function to get the total balance
(define-read-only (get-balance)
(ok (var-get total-deposits))
)
;; Read-only function to get the total amount owed by the user.
(define-read-only (get-amount-owed)
(let (
;; Fetch current loan details or default to initial values.
(current-loan-details (default-to {
amount: u0,
last-interaction-block: u0,
}
(map-get? loans tx-sender)
))
;; Calculate accrued interest on the current loan.
(accrued-interest (calculate-accrued-interest (get amount current-loan-details)
(get last-interaction-block current-loan-details)
))
;; Calculate the total amount due including interest.
(total-due (+ (get amount current-loan-details) (unwrap-panic accrued-interest)))
)
;; Return the total amount due.
(ok total-due)
)
)
;; Public function for users to repay their STX loans.
(define-public (repay (amount uint))
(let (
;; Fetch current loan details or default to initial values.
(current-loan-details (default-to {
amount: u0,
last-interaction-block: u0,
}
(map-get? loans tx-sender)
))
;; Calculate accrued interest since the last interaction.
(accrued-interest (unwrap!
(calculate-accrued-interest (get amount current-loan-details)
(get last-interaction-block current-loan-details)
)
err-no-interest
))
;; Calculate the total amount due including accrued interest.
(total-due (+ (get amount current-loan-details) accrued-interest))
)
;; Ensure the repayment amount is not more than the total due.
(asserts! (>= total-due amount) err-overpay)
;; Transfer the repayment amount from the user to the contract.
(try! (stx-transfer? amount tx-sender current-contract))
;; Update the user's loan details in the map with the new total due.
(map-set loans tx-sender {
amount: (- total-due amount),
last-interaction-block: burn-block-height,
})
;; Update the pool reserve with the paid interest.
(var-set pool-reserve (+ (var-get pool-reserve) accrued-interest))
;; Return success.
(ok true)
)
)
;; Public function for users to claim their yield based on the pool reserve and their deposits.
(define-public (claim-yield)
(let (
;; Fetch user's deposit amount or default to 0.
(user-deposit (default-to u0 (get amount (map-get? deposits { owner: tx-sender }))))
;; Calculate the yield amount based on user's share of the pool.
(yield-amount (/ (* (var-get pool-reserve) user-deposit) (var-get total-deposits)))
)
;; Transfer the yield amount from the contract to the user.
(let ((recipient tx-sender))
(try! (as-contract? ((with-stx yield-amount))
(try! (stx-transfer? yield-amount current-contract recipient))
))
)
;; Update the pool reserve by subtracting the claimed yield.
(var-set pool-reserve (- (var-get pool-reserve) yield-amount))
;; Return success.
(ok true)
)
)
;; Private function to calculate the accrued interest on a loan.
(define-private (calculate-accrued-interest
(principal uint)
(start-block uint)
)
(let (
;; Calculate the number of blocks elapsed since the last interaction.
(elapsed-blocks (- burn-block-height start-block))
;; Calculate the interest based on the principal, rate, and elapsed time.
(interest (/ (* principal (var-get loan-interest-rate) elapsed-blocks) u10000))
)
;; Ensure the loan started in the past (not at block 0).
(asserts! (not (is-eq start-block u0)) (ok u0))
;; Return the calculated interest.
(ok interest)
)
)