Source Code

(impl-trait 'SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-semi-fungible-token-trait.sip013-semi-fungible-token-trait)
(impl-trait 'SPDBEG5X8XD50SPM1JJH0E5CTXGDV5NJTKAKKR5V.sip013-transfer-many-trait.sip013-transfer-many-trait)

(define-fungible-token semi-fungible-token)
(define-non-fungible-token semi-fungible-token-id {
  token-id: uint,
  owner: principal,
})
(define-map token-balances
  {
    token-id: uint,
    owner: principal,
  }
  uint
)
(define-map token-supplies
  uint
  uint
)

(define-constant contract-owner tx-sender)

(define-constant err-owner-only (err u100))
(define-constant err-insufficient-balance (err u1))
(define-constant err-invalid-sender (err u4))

(define-private (set-balance
    (token-id uint)
    (balance uint)
    (owner principal)
  )
  (map-set token-balances {
    token-id: token-id,
    owner: owner,
  } balance
  )
)

(define-private (get-balance-uint
    (token-id uint)
    (who principal)
  )
  (default-to u0
    (map-get? token-balances {
      token-id: token-id,
      owner: who,
    })
  )
)

(define-read-only (get-balance
    (token-id uint)
    (who principal)
  )
  (ok (get-balance-uint token-id who))
)

(define-read-only (get-overall-balance (who principal))
  (ok (ft-get-balance semi-fungible-token who))
)

(define-read-only (get-total-supply (token-id uint))
  (ok (default-to u0 (map-get? token-supplies token-id)))
)

(define-read-only (get-overall-supply)
  (ok (ft-get-supply semi-fungible-token))
)

(define-read-only (get-decimals (token-id uint))
  (ok u0)
)

(define-read-only (get-token-uri (token-id uint))
  (ok none)
)

;; #[allow(unchecked_params)]
(define-public (transfer
    (token-id uint)
    (amount uint)
    (sender principal)
    (recipient principal)
  )
  (let ((sender-balance (get-balance-uint token-id sender)))
    (asserts! (or (is-eq sender tx-sender) (is-eq sender contract-caller))
      err-invalid-sender
    )
    (asserts! (<= amount sender-balance) err-insufficient-balance)
    (try! (ft-transfer? semi-fungible-token amount sender recipient))
    (try! (tag-nft-token-id {
      token-id: token-id,
      owner: sender,
    }))
    (try! (tag-nft-token-id {
      token-id: token-id,
      owner: recipient,
    }))
    (set-balance token-id (- sender-balance amount) sender)
    (set-balance token-id (+ (get-balance-uint token-id recipient) amount)
      recipient
    )
    (print {
      type: "sft_transfer",
      token-id: token-id,
      amount: amount,
      sender: sender,
      recipient: recipient,
    })
    (ok true)
  )
)

(define-public (transfer-memo
    (token-id uint)
    (amount uint)
    (sender principal)
    (recipient principal)
    (memo (buff 34))
  )
  (begin
    (try! (transfer token-id amount sender recipient))
    (print memo)
    (ok true)
  )
)

(define-private (transfer-many-iter
    (item {
      token-id: uint,
      amount: uint,
      sender: principal,
      recipient: principal,
    })
    (previous-response (response bool uint))
  )
  (match previous-response
    prev-ok (transfer (get token-id item) (get amount item) (get sender item)
      (get recipient item)
    )
    prev-err
    previous-response
  )
)

(define-public (transfer-many (transfers (list
  200
  {
    token-id: uint,
    amount: uint,
    sender: principal,
    recipient: principal,
  }
)))
  (fold transfer-many-iter transfers (ok true))
)

(define-private (transfer-many-memo-iter
    (item {
      token-id: uint,
      amount: uint,
      sender: principal,
      recipient: principal,
      memo: (buff 34),
    })
    (previous-response (response bool uint))
  )
  (match previous-response
    prev-ok (transfer-memo (get token-id item) (get amount item) (get sender item)
      (get recipient item) (get memo item)
    )
    prev-err
    previous-response
  )
)

(define-public (transfer-many-memo (transfers (list
  200
  {
    token-id: uint,
    amount: uint,
    sender: principal,
    recipient: principal,
    memo: (buff 34),
  }
)))
  (fold transfer-many-memo-iter transfers (ok true))
)

(define-public (mint
    (token-id uint)
    (amount uint)
    (recipient principal)
  )
  (begin
    (asserts! (is-eq tx-sender contract-owner) err-owner-only)
    (try! (ft-mint? semi-fungible-token amount recipient))
    (try! (tag-nft-token-id {
      token-id: token-id,
      owner: recipient,
    }))
    (set-balance token-id (+ (get-balance-uint token-id recipient) amount)
      recipient
    )
    (map-set token-supplies token-id
      (+ (unwrap-panic (get-total-supply token-id)) amount)
    )
    (print {
      type: "sft_mint",
      token-id: token-id,
      amount: amount,
      recipient: recipient,
    })
    (ok true)
  )
)

(define-private (tag-nft-token-id (nft-token-id {
  token-id: uint,
  owner: principal,
}))
  (begin
    (and
      (is-some (nft-get-owner? semi-fungible-token-id nft-token-id))
      (try! (nft-burn? semi-fungible-token-id nft-token-id (get owner nft-token-id)))
    )
    (nft-mint? semi-fungible-token-id nft-token-id (get owner nft-token-id))
  )
)

Functions (9)

FunctionAccessArgs
get-overall-balanceread-onlywho: principal
get-total-supplyread-onlytoken-id: uint
get-overall-supplyread-only
get-decimalsread-onlytoken-id: uint
get-token-uriread-onlytoken-id: uint
transfer-memopublictoken-id: uint, amount: uint, sender: principal, recipient: principal, memo: (buff 34
transfer-many-iterprivateitem: { token-id: uint, amount: uint, sender: principal, recipient: principal, }, previous-response: (response bool uint
transfer-manypublictransfers: (list 200 { token-id: uint, amount: uint, sender: principal, recipient: principal, }
tag-nft-token-idprivatenft-token-id: { token-id: uint, owner: principal, }