Source Code

;; =====================================================================
;; SIP-010 Fungible Token   0.1% Transfer Tax & Auto-Burn
;; =====================================================================
;;   TESTNET version   uses ST prefix trait address
;; =====================================================================

(impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

;; --------------------------------------------------
;; Error Constants
;; --------------------------------------------------
(define-constant ERR-NOT-AUTHORIZED (err u1000))
(define-constant ERR-NOT-ADMIN (err u1001))
(define-constant ERR-INSUFFICIENT-BALANCE (err u1))
(define-constant ERR-SENDER-EQUALS-RECIPIENT (err u2))
(define-constant ERR-AMOUNT-ZERO (err u3))
(define-constant ERR-SENDER-NOT-TX-SENDER (err u4))
(define-constant ERR-MINT-FAILED (err u1002))
(define-constant ERR-BURN-FAILED (err u1003))
(define-constant ERR-TRANSFER-FAILED (err u1004))
(define-constant ERR-ADMIN-ALREADY-SET (err u1005))
(define-constant ERR-INVALID-PRINCIPAL (err u1006))
(define-constant ERR-AMOUNT-BELOW-MINIMUM (err u1007))

;; --------------------------------------------------
;; Token Definition
;; --------------------------------------------------
(define-fungible-token PAULO u1000000000000000)

;; --------------------------------------------------
;; Constants
;; --------------------------------------------------
(define-constant CONTRACT-DEPLOYER tx-sender)
(define-constant TOKEN-NAME "PAULO")
(define-constant TOKEN-SYMBOL "PAULO")
(define-constant TOKEN-DECIMALS u6)
(define-constant TOKEN-TOTAL-SUPPLY u1000000000000000)
(define-constant TAX-NUMERATOR u1)
(define-constant TAX-DENOMINATOR u1000)
(define-constant TOKEN-URI u"https://amethyst-voluntary-rat-144.mypinata.cloud/ipfs/bafkreifcxnom27jrgmjsdx2qtuphfnqynbju262m6vus56svu7talosp5q")
(define-constant MIN-TRANSFER-NON-EXEMPT u1000)
(define-constant BURN-ADDRESS 'SP000000000000000000002Q6VF78)

;; --------------------------------------------------
;; Data Variables
;; --------------------------------------------------
(define-data-var contract-owner principal CONTRACT-DEPLOYER)
(define-data-var admin principal CONTRACT-DEPLOYER)
(define-data-var total-burned uint u0)

;; --------------------------------------------------
;; Data Maps
;; --------------------------------------------------
(define-map tax-exempt-list principal bool)

;; --------------------------------------------------
;; Private Functions
;; --------------------------------------------------
(define-private (check-is-owner)
  (is-eq tx-sender (var-get contract-owner))
)

(define-private (check-is-admin)
  (is-eq tx-sender (var-get admin))
)

(define-private (check-tax-exempt (account principal))
  (default-to false (map-get? tax-exempt-list account))
)

(define-private (calculate-tax (amount uint))
  (/ (* amount TAX-NUMERATOR) TAX-DENOMINATOR)
)

(define-private (transfer-with-tax
    (amount uint)
    (sender principal)
    (recipient principal)
    (memo (optional (buff 34)))
  )
  (let
    (
      (sender-exempt (check-tax-exempt sender))
      (recipient-exempt (check-tax-exempt recipient))
      (any-exempt (or sender-exempt recipient-exempt))
      (tax-amount (if any-exempt u0 (calculate-tax amount)))
      (transfer-amount (- amount tax-amount))
    )
    (asserts! (> amount u0) ERR-AMOUNT-ZERO)
    (asserts! (is-eq sender tx-sender) ERR-SENDER-NOT-TX-SENDER)
    (asserts! (not (is-eq sender recipient)) ERR-SENDER-EQUALS-RECIPIENT)
    (asserts! (or any-exempt (>= amount MIN-TRANSFER-NON-EXEMPT))
      ERR-AMOUNT-BELOW-MINIMUM
    )

    (if (> tax-amount u0)
      (begin
        (try! (ft-burn? PAULO tax-amount sender))
        (var-set total-burned (+ (var-get total-burned) tax-amount))
      )
      true
    )

    (try! (ft-transfer? PAULO transfer-amount sender recipient))
    (match memo to-print (print to-print) 0x)
    (ok true)
  )
)

(define-private (set-exempt-iter (account principal) (prev-result (response bool uint)))
  (match prev-result
    success
      (begin
        (map-set tax-exempt-list account success)
        (ok success)
      )
    err-val (err err-val)
  )
)

;; --------------------------------------------------
;; SIP-010 Interface
;; --------------------------------------------------
(define-public (transfer
    (amount uint)
    (sender principal)
    (recipient principal)
    (memo (optional (buff 34)))
  )
  (transfer-with-tax amount sender recipient memo)
)

(define-read-only (get-name)
  (ok TOKEN-NAME)
)

(define-read-only (get-symbol)
  (ok TOKEN-SYMBOL)
)

(define-read-only (get-decimals)
  (ok TOKEN-DECIMALS)
)

(define-read-only (get-balance (account principal))
  (ok (ft-get-balance PAULO account))
)

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

(define-read-only (get-token-uri)
  (ok (some TOKEN-URI))
)

;; --------------------------------------------------
;; Admin & Governance
;; --------------------------------------------------
(define-public (set-admin (new-admin principal))
  (begin
    (asserts! (check-is-admin) ERR-NOT-ADMIN)
    (asserts! (not (is-eq new-admin BURN-ADDRESS)) ERR-INVALID-PRINCIPAL)
    (var-set admin new-admin)
    (ok true)
  )
)

(define-public (set-tax-exempt (account principal) (exempt bool))
  (begin
    (asserts! (check-is-admin) ERR-NOT-ADMIN)
    (map-set tax-exempt-list account exempt)
    (ok true)
  )
)

(define-public (set-tax-exempt-many (accounts (list 200 principal)) (exempt bool))
  (begin
    (asserts! (check-is-admin) ERR-NOT-ADMIN)
    (fold set-exempt-iter accounts (ok exempt))
  )
)

(define-public (renounce-ownership)
  (begin
    (asserts! (check-is-owner) ERR-NOT-AUTHORIZED)
    (var-set contract-owner BURN-ADDRESS)
    (ok true)
  )
)

(define-public (transfer-ownership (new-owner principal))
  (begin
    (asserts! (check-is-owner) ERR-NOT-AUTHORIZED)
    (asserts! (not (is-eq new-owner BURN-ADDRESS)) ERR-INVALID-PRINCIPAL)
    (var-set contract-owner new-owner)
    (ok true)
  )
)

;; --------------------------------------------------
;; Read-Only Utility
;; --------------------------------------------------
(define-read-only (get-contract-owner)
  (ok (var-get contract-owner))
)

(define-read-only (get-admin)
  (ok (var-get admin))
)

(define-read-only (get-is-tax-exempt (account principal))
  (ok (check-tax-exempt account))
)

(define-read-only (get-total-burned)
  (ok (var-get total-burned))
)

(define-read-only (get-tax-rate)
  (ok {numerator: TAX-NUMERATOR, denominator: TAX-DENOMINATOR})
)

(define-read-only (get-min-transfer)
  (ok MIN-TRANSFER-NON-EXEMPT)
)

(define-read-only (get-initial-total-supply)
  (ok TOKEN-TOTAL-SUPPLY)
)

;; --------------------------------------------------
;; Initialization
;; --------------------------------------------------
(begin
  (try! (ft-mint? PAULO TOKEN-TOTAL-SUPPLY CONTRACT-DEPLOYER))
  (map-set tax-exempt-list CONTRACT-DEPLOYER true)
  (map-set tax-exempt-list (as-contract tx-sender) true)
  (map-set tax-exempt-list BURN-ADDRESS true)
)

Functions (25)

FunctionAccessArgs
check-is-ownerprivate
check-is-adminprivate
check-tax-exemptprivateaccount: principal
calculate-taxprivateamount: uint
transfer-with-taxprivateamount: uint, sender: principal, recipient: principal, memo: (optional (buff 34
set-exempt-iterprivateaccount: principal, prev-result: (response bool uint
transferpublicamount: uint, sender: principal, recipient: principal, memo: (optional (buff 34
get-nameread-only
get-symbolread-only
get-decimalsread-only
get-balanceread-onlyaccount: principal
get-total-supplyread-only
get-token-uriread-only
set-adminpublicnew-admin: principal
set-tax-exemptpublicaccount: principal, exempt: bool
set-tax-exempt-manypublicaccounts: (list 200 principal
renounce-ownershippublic
transfer-ownershippublicnew-owner: principal
get-contract-ownerread-only
get-adminread-only
get-is-tax-exemptread-onlyaccount: principal
get-total-burnedread-only
get-tax-rateread-only
get-min-transferread-only
get-initial-total-supplyread-only