Source Code

;; Title: Fenrir, Corgi of Ragnarok
;; Author: rozar.btc

;; In the mystical realm of Asgard, there lived a colossal creature named Fenrir, feared by the gods and prophesied to bring about the end of the world. 
;; However, Fenrir was not a fearsome wolf but a massive Welsh Corgi with an insatiable appetite for adventure and mischief. 
;; This unexpected revelation came to light when Odin, the All-Father, embarked on a quest to find and confront Fenrir. 
;; Instead of a terrifying beast, he discovered a playful and mischievous Corgi eager to join his adventure.
;;
;; News of Fenrir's true nature spread throughout Asgard, and the gods were left in awe of the unlikely duo. 
;; The prophecy of Ragnarok was averted, not through force or violence, but through the power of friendship. 
;; And so, the mighty Fenrir, the feared harbinger of doom, was revealed to be nothing more than a massive Welsh Corgi, forever changing the course of Norse mythology.

(impl-trait .dao-traits-v2.sip010-ft-trait)
(impl-trait .dao-traits-v2.extension-trait)
(impl-trait .dao-traits-v2.liquid-ft-trait)
(impl-trait .dao-traits-v2.craftable-trait)

(use-trait liquid-ft-trait .dao-traits-v2.liquid-ft-trait)

(define-constant err-unauthorized (err u3000))
(define-constant err-not-token-owner (err u4))

(define-constant ONE_6 (pow u10 u6)) ;; 6 decimal places

(define-constant contract (as-contract tx-sender))

(define-fungible-token fenrir)

(define-data-var token-name (string-ascii 32) "Fenrir, Corgi of Ragnarok")
(define-data-var token-symbol (string-ascii 10) "FENRIR")
(define-data-var token-uri (optional (string-utf8 256)) (some u"https://charisma.rocks/fenrir.json"))
(define-data-var token-decimals uint u0)

(define-data-var craft-reward-factor uint u0)
(define-data-var salvage-reward-factor uint u0)
(define-data-var transfer-reward-factor uint u0)

(define-data-var craft-fee-percent uint u100) ;; 0.01%
(define-data-var salvage-fee-percent uint u1000) ;; 0.1%
(define-data-var transfer-fee-percent uint u10000) ;; 1%

;; --- Authorization check

(define-read-only (is-dao-or-extension)
	(ok (asserts! (or (is-eq tx-sender 'SP2D5BGGJ956A635JG7CJQ59FTRFRB0893514EZPJ.dungeon-master) (contract-call? 'SP2D5BGGJ956A635JG7CJQ59FTRFRB0893514EZPJ.dungeon-master is-extension contract-caller)) err-unauthorized))
)

;; --- Internal DAO functions

(define-public (set-name (new-name (string-ascii 32)))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set token-name new-name))
	)
)

(define-public (set-symbol (new-symbol (string-ascii 10)))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set token-symbol new-symbol))
	)
)

(define-public (set-decimals (new-decimals uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set token-decimals new-decimals))
	)
)

(define-public (set-token-uri (new-uri (optional (string-utf8 256))))
	(begin
		(try! (is-dao-or-extension))
		(var-set token-uri new-uri)
		(ok 
			(print {
				notification: "token-metadata-update",
				payload: {
					token-class: "ft",
					contract-id: (as-contract tx-sender)
				}
			})
		)
	)
)

(define-public (set-craft-reward-factor (new-craft-reward-factor uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set craft-reward-factor new-craft-reward-factor))
	)
)

(define-public (set-salvage-reward-factor (new-salvage-reward-factor uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set salvage-reward-factor new-salvage-reward-factor))
	)
)

(define-public (set-transfer-reward-factor (new-transfer-reward-factor uint))
	(begin
		(try! (is-dao-or-extension))
		(ok (var-set transfer-reward-factor new-transfer-reward-factor))
	)
)

(define-public (set-craft-fee-percent (new-craft-fee-percent uint))
	(begin
		(try! (is-dao-or-extension))
        (asserts! (<= new-craft-fee-percent u50000) err-unauthorized)
		(ok (var-set craft-fee-percent new-craft-fee-percent))
	)
)

(define-public (set-salvage-fee-percent (new-salvage-fee-percent uint))
	(begin
		(try! (is-dao-or-extension))
        (asserts! (<= new-salvage-fee-percent u50000) err-unauthorized)
		(ok (var-set salvage-fee-percent new-salvage-fee-percent))
	)
)

(define-public (set-transfer-fee-percent (new-transfer-fee-percent uint))
	(begin
		(try! (is-dao-or-extension))
        (asserts! (<= new-transfer-fee-percent u50000) err-unauthorized)
		(ok (var-set transfer-fee-percent new-transfer-fee-percent))
	)
)

(define-public (craft (amount uint) (recipient principal) (lft-a <liquid-ft-trait>) (lft-b <liquid-ft-trait>))
    (let
        (
            (craft-reward (/ (* amount (var-get craft-reward-factor)) ONE_6))
            (craft-fee (/ (* amount (var-get craft-fee-percent)) ONE_6))
        )
		(try! (is-dao-or-extension))
        ;; if craft-fee is greater than 0 then burn base tokens
        (and (> craft-fee u0) 
            (begin
                (print {craft-fee: craft-fee})
                (try! (contract-call? lft-a deflate craft-fee))
                (try! (contract-call? lft-b deflate craft-fee))
            )
        )
        ;; if craft reward is greater than 0 then mint to the recipient
        (and (> craft-reward u0)
            (begin
                (print {craft-reward: craft-reward})
                (try! (as-contract (contract-call? 'SP2D5BGGJ956A635JG7CJQ59FTRFRB0893514EZPJ.dme000-governance-token dmg-mint craft-reward recipient)))
            )
        )
        (join amount recipient lft-a lft-b)
    )
    
)

(define-public (salvage (amount uint) (recipient principal) (lft-a <liquid-ft-trait>) (lft-b <liquid-ft-trait>))
    (let
        (
            (salvage-reward (/ (* amount (var-get salvage-reward-factor)) ONE_6))
            (salvage-fee (/ (* amount (var-get salvage-fee-percent)) ONE_6))
            (amount-after-fee (- amount salvage-fee))
        )
		(try! (is-dao-or-extension))
        ;; if salvage-fee is greater than 0 then burn the fee
        (and (> salvage-fee u0) 
            (begin
                (print {salvage-fee: salvage-fee})
                (try! (deflate salvage-fee))
            )
        )
        ;; if salvage reward is greater than 0 then mint to the recipient
        (and (> salvage-reward u0)
            (begin
                (print {salvage-reward: salvage-reward})
                (try! (as-contract (contract-call? 'SP2D5BGGJ956A635JG7CJQ59FTRFRB0893514EZPJ.dme000-governance-token dmg-mint salvage-reward recipient)))
            )
        )
        (split amount-after-fee recipient lft-a lft-b)
    )
)

;; --- Public functions

(define-public (deflate (amount uint))
    (ft-burn? fenrir amount tx-sender)
)

(define-read-only (get-craft-reward-factor)
	(ok (var-get craft-reward-factor))
)

(define-read-only (get-salvage-reward-factor)
	(ok (var-get salvage-reward-factor))
)

(define-read-only (get-transfer-reward-factor)
	(ok (var-get transfer-reward-factor))
)

(define-read-only (get-craft-fee-percent)
	(ok (var-get craft-fee-percent))
)

(define-read-only (get-salvage-fee-percent)
	(ok (var-get salvage-fee-percent))
)

(define-read-only (get-transfer-fee-percent)
	(ok (var-get transfer-fee-percent))
)

;; sip010-ft-trait

(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
	(let
        (
            (transfer-reward (/ (* amount (var-get transfer-reward-factor)) ONE_6))
            (transfer-fee (/ (* amount (var-get transfer-fee-percent)) ONE_6))
            (amount-after-fee (- amount transfer-fee))
        )
		(asserts! (or (is-eq tx-sender sender) (is-eq contract-caller sender)) err-not-token-owner)
        ;; if transfer-fee is greater than 0 then deflate the fee
        (and (> transfer-fee u0)
            (begin
                (print {tx-fee: transfer-fee})
                (try! (deflate transfer-fee))
            )
        )
        ;; if transfer reward is greater than 0 then mint to the recipient
        (and (> transfer-reward u0)
            (begin
                (print {transfer-reward: transfer-reward})
                (try! (as-contract (contract-call? 'SP2D5BGGJ956A635JG7CJQ59FTRFRB0893514EZPJ.dme000-governance-token dmg-mint transfer-reward recipient)))
            )
        )
		(ft-transfer? fenrir amount-after-fee sender recipient)
	)
)

(define-read-only (get-name)
	(ok (var-get token-name))
)

(define-read-only (get-symbol)
	(ok (var-get token-symbol))
)

(define-read-only (get-decimals)
	(ok (var-get token-decimals))
)

(define-read-only (get-balance (who principal))
	(ok (ft-get-balance fenrir who))
)

(define-read-only (get-total-supply)
	(ok (ft-get-supply fenrir))
)

(define-read-only (get-token-uri)
	(ok (var-get token-uri))
)

;; --- Liquid staking

(define-private (get-total-in-pool (lft <liquid-ft-trait>))
	(unwrap-panic (contract-call? lft get-balance contract))
)

(define-private (get-exchange-rate (lft <liquid-ft-trait>))
	(/ (* (get-total-in-pool lft) ONE_6) (ft-get-supply fenrir))
)

;; --- Crafting

(define-private (join (amount uint) (recipient principal) (lft-a <liquid-ft-trait>) (lft-b <liquid-ft-trait>))
    (let
        (
            (amount-lft-a (/ (* amount (get-exchange-rate lft-a)) ONE_6))
            (amount-lft-b (/ (* amount (get-exchange-rate lft-b)) ONE_6))
        )
        (print {exchange-rate-a: (get-exchange-rate lft-a), exchange-rate-b: (get-exchange-rate lft-b)})
        (try! (contract-call? lft-a transfer amount-lft-a tx-sender contract none))
        (try! (contract-call? lft-b transfer amount-lft-b tx-sender contract none))
        (try! (ft-mint? fenrir amount recipient))
        (ok true)
    )
)

(define-private (split (amount uint) (recipient principal) (lft-a <liquid-ft-trait>) (lft-b <liquid-ft-trait>))
    (let
        (
            (amount-lft-a (/ (* amount (get-exchange-rate lft-a)) ONE_6))
            (amount-lft-b (/ (* amount (get-exchange-rate lft-b)) ONE_6))
        )
        (print {exchange-rate-a: (get-exchange-rate lft-a), exchange-rate-b: (get-exchange-rate lft-b)})
        (try! (ft-burn? fenrir amount tx-sender))
        (try! (contract-call? lft-a transfer amount-lft-a contract recipient none))
        (try! (contract-call? lft-b transfer amount-lft-b contract recipient none))
        (ok true)
    )
)

;; --- Extension callback

(define-public (callback (sender principal) (memo (buff 34)))
	(ok true)
)

;; --- Init

(ft-mint? fenrir u1 contract)

Functions (32)

FunctionAccessArgs
is-dao-or-extensionread-only
set-namepublicnew-name: (string-ascii 32
set-symbolpublicnew-symbol: (string-ascii 10
set-decimalspublicnew-decimals: uint
set-token-uripublicnew-uri: (optional (string-utf8 256
set-craft-reward-factorpublicnew-craft-reward-factor: uint
set-salvage-reward-factorpublicnew-salvage-reward-factor: uint
set-transfer-reward-factorpublicnew-transfer-reward-factor: uint
set-craft-fee-percentpublicnew-craft-fee-percent: uint
set-salvage-fee-percentpublicnew-salvage-fee-percent: uint
set-transfer-fee-percentpublicnew-transfer-fee-percent: uint
craftpublicamount: uint, recipient: principal, lft-a: <liquid-ft-trait>, lft-b: <liquid-ft-trait>
salvagepublicamount: uint, recipient: principal, lft-a: <liquid-ft-trait>, lft-b: <liquid-ft-trait>
deflatepublicamount: uint
get-craft-reward-factorread-only
get-salvage-reward-factorread-only
get-transfer-reward-factorread-only
get-craft-fee-percentread-only
get-salvage-fee-percentread-only
get-transfer-fee-percentread-only
transferpublicamount: uint, sender: principal, recipient: principal, memo: (optional (buff 34
get-nameread-only
get-symbolread-only
get-decimalsread-only
get-balanceread-onlywho: principal
get-total-supplyread-only
get-token-uriread-only
get-total-in-poolprivatelft: <liquid-ft-trait>
get-exchange-rateprivatelft: <liquid-ft-trait>
joinprivateamount: uint, recipient: principal, lft-a: <liquid-ft-trait>, lft-b: <liquid-ft-trait>
splitprivateamount: uint, recipient: principal, lft-a: <liquid-ft-trait>, lft-b: <liquid-ft-trait>
callbackpublicsender: principal, memo: (buff 34