Source Code

;; UWU FACTORY CONTRACT V1
;; UWU Protocol Version 1.0.0

;; This file is part of UWU Protocol.

;; UWU Protocol is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.

;; UWU Protocol is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with UWU Protocol. If not, see <http://www.gnu.org/licenses/>.

(define-constant ERR_NOT_AUTHORIZED (err u1001))
(define-constant ERR_INVALID_AMOUNT (err u1002))
(define-constant ERR_VAULT_NOT_FOUND (err u2001))
(define-constant ERR_VAULT_LIMIT (err u2002))
(define-constant ERR_VAULT_NOT_LIQUIDATED (err u2003))
(define-constant ERR_VAULT_LIQUIDATED (err u2004))
(define-constant ERR_MINIMUM_DEBT (err u3001))
(define-constant ERR_MAXIMUM_DEBT (err u3002))
(define-constant ERR_NONZERO_DEBT (err u3003))
(define-constant ERR_ZERO_DEBT (err u3004))

(define-data-var last-vault-id uint u0)
(define-data-var opened-vault-count uint u0)
(define-data-var liquidated-vault-count uint u0)

(define-map vaults uint {id: uint, owner: principal, collateral: uint, debt: uint, height: uint, liquidated: bool})
(define-map vault-entries principal (list 20 uint))
(define-map last-removed-entry principal uint)

(define-read-only (get-last-vault-id)
  (ok (var-get last-vault-id))
)

(define-read-only (get-opened-vault-count)
  (ok (var-get opened-vault-count))
)

(define-read-only (get-liquidated-vault-count)
  (ok (var-get liquidated-vault-count))
)

(define-read-only (get-vault-by-id (id uint))
  (ok (map-get? vaults id))
)

(define-read-only (get-vault-entries (account principal))
  (ok (default-to (list ) (map-get? vault-entries account)))
)

(define-read-only (get-vaults (account principal))
  (let (
    (entries (unwrap-panic (get-vault-entries account)))
  )
    (ok (map get-vault-by-id entries))
  )
)

(define-read-only (get-can-liquidate-vault (id uint))
  (let (
    (vault (default-to {collateral: u0, debt: u0} (map-get? vaults id)))
    (oracle (unwrap-panic (get-stx-price)))
  )
    (begin
      (asserts! (and (> (get collateral vault) u0) (> (get debt vault) u0)) (ok {can-liquidate: false, collateral-ratio: u0}))
      (ok {can-liquidate: (< (/ (/ (* (get collateral vault) oracle) (get debt vault)) u10000) u150), collateral-ratio: (/ (/ (* (get collateral vault) oracle) (get debt vault)) u10000)})
    )
  )
)

(define-public (get-stx-price)
  (ok (unwrap-panic (contract-call? .uwu-oracle-proxy-v1 get-stx-price)))
)

(define-public (open-vault (amount uint) (debt uint))
  (let (
    (sender tx-sender)
    (entries (unwrap-panic (get-vault-entries tx-sender)))
    (id (+ (var-get last-vault-id) u1))
    (oracle (unwrap-panic (get-stx-price)))
  )
    (begin
      (asserts! (>= debt u25000000) ERR_MINIMUM_DEBT)
      (asserts! (>= (/ (/ (* amount oracle) debt) u10000) u150) ERR_MAXIMUM_DEBT)
      (try! (stx-transfer? amount sender (as-contract tx-sender)))
      (try! (as-contract (contract-call? .uwu-token-v1 mint (- debt (/ (* debt u200) u10000)) sender)))
      (try! (as-contract (contract-call? .uwu-token-v1 mint (/ (* debt u200) u10000) .xuwu-fee-claim-v1)))
      (var-set last-vault-id id)
      (var-set opened-vault-count (+ (var-get opened-vault-count) u1))
      (map-set vaults id {id: id, owner: sender, collateral: amount, debt: debt, height: block-height, liquidated: false})
      (map-set vault-entries sender (unwrap! (as-max-len? (append entries id) u20) ERR_VAULT_LIMIT))
      (print {action: "open-vault", sender: sender, id: id, owner: sender, collateral: amount, debt: debt})
      (ok true)
    )
  )
)

(define-public (borrow-vault (id uint) (amount uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
    (oracle (unwrap-panic (get-stx-price)))
  )
    (begin
      (asserts! (is-eq (get owner vault) sender) ERR_NOT_AUTHORIZED)
      (asserts! (is-eq (get liquidated vault) false) ERR_VAULT_LIQUIDATED)
      (asserts! (>= (+ (get debt vault) amount) u25000000) ERR_MINIMUM_DEBT)
      (asserts! (>= (/ (/ (* (get collateral vault) oracle) (+ (get debt vault) amount)) u10000) u150) ERR_MAXIMUM_DEBT)
      (try! (as-contract (contract-call? .uwu-token-v1 mint amount sender)))
      (map-set vaults id (merge vault {debt: (+ (get debt vault) amount)}))
      (print {action: "borrow-vault", sender: sender, id: id, owner: (get owner vault), amount: amount, collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-public (collateralize-vault (id uint) (amount uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
  )
    (begin
      (asserts! (is-eq (get owner vault) sender) ERR_NOT_AUTHORIZED)
      (asserts! (is-eq (get liquidated vault) false) ERR_VAULT_LIQUIDATED)
      (try! (stx-transfer? amount sender (as-contract tx-sender)))
      (map-set vaults id (merge vault {collateral: (+ (get collateral vault) amount)}))
      (print {action: "collateralize-vault", sender: sender, id: id, owner: (get owner vault), amount: amount, collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-public (repay-vault (id uint) (amount uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
  )
    (begin
      (asserts! (is-eq (get owner vault) sender) ERR_NOT_AUTHORIZED)
      (asserts! (is-eq (get liquidated vault) false) ERR_VAULT_LIQUIDATED)
      (asserts! (> (get debt vault) u0) ERR_ZERO_DEBT)
      (asserts! (<= amount (get debt vault)) ERR_INVALID_AMOUNT)
      (asserts! (or (is-eq amount (get debt vault)) (>= (- (get debt vault) amount) u25000000)) ERR_MINIMUM_DEBT)
      (try! (as-contract (contract-call? .uwu-token-v1 burn amount sender)))
      (map-set vaults id (merge vault {debt: (- (get debt vault) amount)}))
      (print {action: "repay-vault", sender: sender, id: id, owner: (get owner vault), amount: amount, collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-public (close-vault (id uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
    (entries (unwrap-panic (get-vault-entries tx-sender)))
  )
    (begin
      (asserts! (is-eq (get owner vault) sender) ERR_NOT_AUTHORIZED)
      (asserts! (is-eq (get liquidated vault) false) ERR_VAULT_LIQUIDATED)
      (asserts! (is-eq (get debt vault) u0) ERR_NONZERO_DEBT)
      (try! (as-contract (stx-transfer? (get collateral vault) tx-sender sender)))
      (var-set opened-vault-count (- (var-get opened-vault-count) u1))
      (map-delete vaults id)
      (map-set last-removed-entry sender id)
      (map-set vault-entries sender (filter remove-vault-entry entries))
      (print {action: "close-vault", sender: sender, id: id, owner: (get owner vault), collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-public (init-liquidate-vault (id uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
    (oracle (unwrap-panic (get-stx-price)))
  )
    (begin
      (asserts! (is-eq (get liquidated vault) false) ERR_VAULT_LIQUIDATED)
      (asserts! (> (get debt vault) u0) ERR_ZERO_DEBT)
      (asserts! (< (/ (/ (* (get collateral vault) oracle) (get debt vault)) u10000) u150) ERR_VAULT_NOT_LIQUIDATED)
      (var-set opened-vault-count (- (var-get opened-vault-count) u1))
      (var-set liquidated-vault-count (+ (var-get liquidated-vault-count) u1))
      (map-set vaults id (merge vault {liquidated: true}))
      (print {action: "init-liquidate-vault", sender: sender, id: id, owner: (get owner vault), collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-public (liquidate-vault (id uint) (amount uint))
  (let (
    (sender tx-sender)
    (vault (unwrap! (map-get? vaults id) ERR_VAULT_NOT_FOUND))
  )
    (begin
      (asserts! (is-eq (get liquidated vault) true) ERR_VAULT_NOT_LIQUIDATED)
      (asserts! (and (> (get collateral vault) u0) (> (get debt vault) u0)) ERR_VAULT_LIQUIDATED)
      (asserts! (<= amount (get debt vault)) ERR_INVALID_AMOUNT)
      (asserts! (or (is-eq amount (get debt vault)) (>= (- (get debt vault) amount) u25000000)) ERR_MINIMUM_DEBT)
      (try! (as-contract (contract-call? .uwu-token-v1 burn amount sender)))
      (try! (as-contract (stx-transfer? (/ (* (get collateral vault) (/ (* amount u10000) (get debt vault))) u10000) tx-sender sender)))
      (map-set vaults id (merge vault {collateral: (- (get collateral vault) (/ (* (get collateral vault) (/ (* amount u10000) (get debt vault))) u10000)), debt: (- (get debt vault) amount)}))
      (print {action: "liquidate-vault", sender: sender, id: id, owner: (get owner vault), collateral: (get collateral vault), debt: (get debt vault)})
      (ok true)
    )
  )
)

(define-private (remove-vault-entry (id uint))
  (let (
    (entry (unwrap-panic (map-get? last-removed-entry tx-sender)))
  )
    (if (is-eq id entry)
      false
      true
    )
  )
)

Functions (16)

FunctionAccessArgs
get-last-vault-idread-only
get-opened-vault-countread-only
get-liquidated-vault-countread-only
get-vault-by-idread-onlyid: uint
get-vault-entriesread-onlyaccount: principal
get-vaultsread-onlyaccount: principal
get-can-liquidate-vaultread-onlyid: uint
get-stx-pricepublic
open-vaultpublicamount: uint, debt: uint
borrow-vaultpublicid: uint, amount: uint
collateralize-vaultpublicid: uint, amount: uint
repay-vaultpublicid: uint, amount: uint
close-vaultpublicid: uint
init-liquidate-vaultpublicid: uint
liquidate-vaultpublicid: uint, amount: uint
remove-vault-entryprivateid: uint