Source Code

;; Credit Delegation Contract
;; Lend your reputation to trusted parties and earn fees

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u700))
(define-constant err-not-found (err u701))
(define-constant err-unauthorized (err u702))
(define-constant err-insufficient-credit (err u703))
(define-constant err-already-delegated (err u704))
(define-constant err-delegation-expired (err u705))

;; Default delegation fee: 10%
(define-constant default-delegation-fee u1000)

;; Data Variables
(define-data-var delegation-nonce uint u0)

;; Data Maps
(define-map credit-delegations
  { delegation-id: uint }
  {
    delegator: principal,
    delegatee: principal,
    credit-limit: uint,
    used-credit: uint,
    fee-rate: uint,
    start-block: uint,
    end-block: uint,
    active: bool
  }
)

(define-map delegator-stats
  { delegator: principal }
  {
    total-delegated: uint,
    active-delegations: uint,
    fees-earned: uint,
    defaults: uint
  }
)

(define-map delegatee-stats
  { delegatee: principal }
  {
    total-borrowed: uint,
    active-borrows: uint,
    total-repaid: uint,
    defaults: uint
  }
)

(define-map active-delegation
  { delegator: principal, delegatee: principal }
  { delegation-id: uint, active: bool }
)

;; Read-only functions
(define-read-only (get-delegation (delegation-id uint))
  (map-get? credit-delegations { delegation-id: delegation-id })
)

(define-read-only (get-delegator-stats (delegator principal))
  (default-to
    { total-delegated: u0, active-delegations: u0, fees-earned: u0, defaults: u0 }
    (map-get? delegator-stats { delegator: delegator })
  )
)

(define-read-only (get-delegatee-stats (delegatee principal))
  (default-to
    { total-borrowed: u0, active-borrows: u0, total-repaid: u0, defaults: u0 }
    (map-get? delegatee-stats { delegatee: delegatee })
  )
)

(define-read-only (get-available-credit (delegation-id uint))
  (let
    (
      (delegation (unwrap! (get-delegation delegation-id) (err err-not-found)))
    )
    (ok (- (get credit-limit delegation) (get used-credit delegation)))
  )
)

(define-read-only (has-active-delegation (delegator principal) (delegatee principal))
  (default-to false
    (get active (map-get? active-delegation { delegator: delegator, delegatee: delegatee })))
)

;; Public functions

;; Delegate credit to another user
(define-public (delegate-credit
  (delegatee principal)
  (credit-limit uint)
  (fee-rate uint)
  (duration uint))
  (let
    (
      (delegation-id (var-get delegation-nonce))
    )
    (asserts! (not (has-active-delegation tx-sender delegatee)) err-already-delegated)
    (asserts! (> credit-limit u0) err-insufficient-credit)
    
    ;; Create delegation
    (map-set credit-delegations
      { delegation-id: delegation-id }
      {
        delegator: tx-sender,
        delegatee: delegatee,
        credit-limit: credit-limit,
        used-credit: u0,
        fee-rate: fee-rate,
        start-block: stacks-block-height,
        end-block: (+ stacks-block-height duration),
        active: true
      }
    )
    
    ;; Mark as active
    (map-set active-delegation
      { delegator: tx-sender, delegatee: delegatee }
      { delegation-id: delegation-id, active: true }
    )
    
    ;; Update delegator stats
    (let
      (
        (stats (get-delegator-stats tx-sender))
      )
      (map-set delegator-stats
        { delegator: tx-sender }
        {
          total-delegated: (+ (get total-delegated stats) credit-limit),
          active-delegations: (+ (get active-delegations stats) u1),
          fees-earned: (get fees-earned stats),
          defaults: (get defaults stats)
        }
      )
    )
    
    (var-set delegation-nonce (+ delegation-id u1))
    (ok delegation-id)
  )
)

;; Borrow using delegated credit
(define-public (borrow-delegated-credit
  (delegation-id uint)
  (amount uint))
  (let
    (
      (delegation (unwrap! (get-delegation delegation-id) err-not-found))
      (available (unwrap! (get-available-credit delegation-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get delegatee delegation)) err-unauthorized)
    (asserts! (get active delegation) err-delegation-expired)
    (asserts! (<= stacks-block-height (get end-block delegation)) err-delegation-expired)
    (asserts! (<= amount available) err-insufficient-credit)
    
    ;; Update used credit
    (map-set credit-delegations
      { delegation-id: delegation-id }
      (merge delegation { used-credit: (+ (get used-credit delegation) amount) })
    )
    
    ;; Update delegatee stats
    (let
      (
        (stats (get-delegatee-stats tx-sender))
      )
      (map-set delegatee-stats
        { delegatee: tx-sender }
        {
          total-borrowed: (+ (get total-borrowed stats) amount),
          active-borrows: (+ (get active-borrows stats) u1),
          total-repaid: (get total-repaid stats),
          defaults: (get defaults stats)
        }
      )
    )
    
    (ok amount)
  )
)

;; Repay delegated credit
(define-public (repay-delegated-credit
  (delegation-id uint)
  (amount uint))
  (let
    (
      (delegation (unwrap! (get-delegation delegation-id) err-not-found))
      (fee (/ (* amount (get fee-rate delegation)) u10000))
      (principal-repayment (- amount fee))
    )
    (asserts! (is-eq tx-sender (get delegatee delegation)) err-unauthorized)
    (asserts! (<= amount (get used-credit delegation)) err-insufficient-credit)
    
    ;; Transfer fee to delegator
    (try! (stx-transfer? fee tx-sender (get delegator delegation)))
    
    ;; Update used credit
    (map-set credit-delegations
      { delegation-id: delegation-id }
      (merge delegation { used-credit: (- (get used-credit delegation) principal-repayment) })
    )
    
    ;; Update delegator stats (fees earned)
    (let
      (
        (stats (get-delegator-stats (get delegator delegation)))
      )
      (map-set delegator-stats
        { delegator: (get delegator delegation) }
        (merge stats { fees-earned: (+ (get fees-earned stats) fee) })
      )
    )
    
    ;; Update delegatee stats
    (let
      (
        (stats (get-delegatee-stats tx-sender))
      )
      (map-set delegatee-stats
        { delegatee: tx-sender }
        {
          total-borrowed: (get total-borrowed stats),
          active-borrows: (- (get active-borrows stats) u1),
          total-repaid: (+ (get total-repaid stats) principal-repayment),
          defaults: (get defaults stats)
        }
      )
    )
    
    (ok { repaid: principal-repayment, fee: fee })
  )
)

;; Revoke credit delegation
(define-public (revoke-delegation (delegation-id uint))
  (let
    (
      (delegation (unwrap! (get-delegation delegation-id) err-not-found))
    )
    (asserts! (is-eq tx-sender (get delegator delegation)) err-unauthorized)
    (asserts! (is-eq (get used-credit delegation) u0) err-insufficient-credit)
    
    ;; Deactivate delegation
    (map-set credit-delegations
      { delegation-id: delegation-id }
      (merge delegation { active: false })
    )
    
    ;; Remove from active
    (map-set active-delegation
      { delegator: (get delegator delegation), delegatee: (get delegatee delegation) }
      { delegation-id: delegation-id, active: false }
    )
    
    ;; Update delegator stats
    (let
      (
        (stats (get-delegator-stats tx-sender))
      )
      (map-set delegator-stats
        { delegator: tx-sender }
        (merge stats { active-delegations: (- (get active-delegations stats) u1) })
      )
    )
    
    (ok true)
  )
)

;; Record default (called by core contract)
(define-public (record-delegation-default (delegation-id uint))
  (let
    (
      (delegation (unwrap! (get-delegation delegation-id) err-not-found))
      (delegator (get delegator delegation))
    )
    ;; Update delegator stats
    (let
      (
        (stats (get-delegator-stats delegator))
      )
      (map-set delegator-stats
        { delegator: delegator }
        (merge stats { defaults: (+ (get defaults stats) u1) })
      )
    )
    
    ;; Update delegatee stats
    (let
      (
        (delegatee (get delegatee delegation))
        (stats (get-delegatee-stats delegatee))
      )
      (map-set delegatee-stats
        { delegatee: delegatee }
        (merge stats { defaults: (+ (get defaults stats) u1) })
      )
    )
    
    (ok true)
  )
)

Functions (10)

FunctionAccessArgs
get-delegationread-onlydelegation-id: uint
get-delegator-statsread-onlydelegator: principal
get-delegatee-statsread-onlydelegatee: principal
get-available-creditread-onlydelegation-id: uint
has-active-delegationread-onlydelegator: principal, delegatee: principal
delegate-creditpublicdelegatee: principal, credit-limit: uint, fee-rate: uint, duration: uint
borrow-delegated-creditpublicdelegation-id: uint, amount: uint
repay-delegated-creditpublicdelegation-id: uint, amount: uint
revoke-delegationpublicdelegation-id: uint
record-delegation-defaultpublicdelegation-id: uint