Source Code

(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_NOT_AUTHORIZED (err u900))
(define-constant ERR_NFT_NOT_FOUND (err u901))
(define-constant ERR_LOAN_NOT_FOUND (err u902))
(define-constant ERR_INSUFFICIENT_COLLATERAL (err u903))

(define-non-fungible-token perpetual-nft uint)

(define-data-var next-nft-id uint u1)
(define-data-var next-loan-id uint u1)

(define-map nft-collateral
  uint
  {
    owner: principal,
    locked-amount: uint,
    locked-at: uint,
    expiry: uint
  }
)

(define-map loans
  uint
  {
    nft-id: uint,
    borrower: principal,
    lender: principal,
    loan-amount: uint,
    interest-rate: uint,
    duration: uint,
    start-time: uint,
    repaid: bool
  }
)

(define-read-only (get-contract-hash)
  (contract-hash? .perpetual-nft)
)

(define-read-only (get-nft-collateral (nft-id uint))
  (ok (unwrap! (map-get? nft-collateral nft-id) ERR_NFT_NOT_FOUND))
)

(define-read-only (get-loan (loan-id uint))
  (ok (unwrap! (map-get? loans loan-id) ERR_LOAN_NOT_FOUND))
)

(define-public (mint-nft (to principal) (locked-amount uint) (expiry uint))
  (let
    (
      (nft-id (var-get next-nft-id))
    )
    (try! (nft-mint? perpetual-nft nft-id to))
    (map-set nft-collateral nft-id {
      owner: to,
      locked-amount: locked-amount,
      locked-at: stacks-block-time,
      expiry: expiry
    })
    (var-set next-nft-id (+ nft-id u1))
    (ok nft-id)
  )
)

(define-public (collateralize 
  (nft-id uint)
  (loan-amount uint)
  (interest-rate uint)
  (duration uint)
  (lender principal)
)
  (let
    (
      (loan-id (var-get next-loan-id))
      (collateral-data (unwrap! (map-get? nft-collateral nft-id) ERR_NFT_NOT_FOUND))
    )
    (asserts! (is-eq (get owner collateral-data) tx-sender) ERR_NOT_AUTHORIZED)
    (asserts! (>= (get locked-amount collateral-data) loan-amount) ERR_INSUFFICIENT_COLLATERAL)
    (map-set loans loan-id {
      nft-id: nft-id,
      borrower: tx-sender,
      lender: lender,
      loan-amount: loan-amount,
      interest-rate: interest-rate,
      duration: duration,
      start-time: stacks-block-time,
      repaid: false
    })
    (var-set next-loan-id (+ loan-id u1))
    (ok loan-id)
  )
)

(define-public (repay-loan (loan-id uint))
  (let
    (
      (loan-data (unwrap! (map-get? loans loan-id) ERR_LOAN_NOT_FOUND))
      (total-repayment (+ (get loan-amount loan-data) 
        (/ (* (get loan-amount loan-data) (get interest-rate loan-data)) u100)))
    )
    (asserts! (is-eq (get borrower loan-data) tx-sender) ERR_NOT_AUTHORIZED)
    (try! (stx-transfer? total-repayment tx-sender (get lender loan-data)))
    (map-set loans loan-id (merge loan-data {repaid: true}))
    (ok true)
  )
)

(define-read-only (view-repay-amount (loan-id uint))
  (let
    (
      (loan-data (unwrap! (map-get? loans loan-id) ERR_LOAN_NOT_FOUND))
    )
    (ok (+ (get loan-amount loan-data) 
      (/ (* (get loan-amount loan-data) (get interest-rate loan-data)) u100)))
  )
)

(define-read-only (get-loan-terms (loan-id uint))
  (ok (unwrap! (map-get? loans loan-id) ERR_LOAN_NOT_FOUND))
)

(define-read-only (verify-secp256r1 (message (buff 32)) (signature (buff 64)) (public-key (buff 33)))
  (ok (secp256r1-verify message signature public-key))
)

(define-read-only (get-timestamp)
  stacks-block-time
)

Functions (9)

FunctionAccessArgs
get-contract-hashread-only
get-nft-collateralread-onlynft-id: uint
get-loanread-onlyloan-id: uint
mint-nftpublicto: principal, locked-amount: uint, expiry: uint
repay-loanpublicloan-id: uint
view-repay-amountread-onlyloan-id: uint
get-loan-termsread-onlyloan-id: uint
verify-secp256r1read-onlymessage: (buff 32
get-timestampread-only