Fungible Token

Smart Contract

A fungible token is stored and transferred in a similar way to how satoshis are stored and transferred in Bitcoin. Its current state is stored in a set of UTXOs. When tokens are transferred a utxo is spent and two new UTXOs are created: one containing the amount sent and one containing the change.

The transfer function checks if the current on-chain object contains a sufficient number of tokens and throws an error if not. If sufficient, the supply of the current on-chain object is reduced by the amount to be sent. A new on-chain object, owned by the recipient and containing the sent amount, is created and returned.

Minimization note: For lower on-chain footprint (and thus lower hygiene dust costs), consider deploying token logic via a taproot module and using small expressions or _url where appropriate. See Fees "User Choices to Control On-Chain Data and Hygiene Dust Costs" and the bare-multisig rationale. Review Legal Notice for compliance.

import { Contract } from '@bitcoin-computer/lib'

class Token extends Contract {
  amount: bigint
  symbol: string
  _owners: string[]

  constructor(to: string, amount: bigint, symbol: string) {
    super({ _owners: [to], amount, symbol })
  }

  transfer(recipient: string, amount: bigint) {
    if (this.amount < amount) throw new Error()

    this.amount -= amount
    return new Token(recipient, amount, this.symbol)
  }
}

Usage

The usage is as in the case of a non-fungible token.

// Create wallets
const sender = new Computer()
const receiver = new Computer()

// Fund sender wallet
await sender.faucet(0.001e8)

// Mint new fungible token with total supply of 10
const token = await sender.new(Token, [sender.getPublicKey(), 10n, 'SYM'])

// Send 2 tokens to receiver
const sentToken = await token.transfer(receiver.getPublicKey(), 2n)

// SentToken will have supply of 2 and token will have a supply of 8
expect(token.amount).eq(8n)
expect(sentToken.amount).eq(2n)

Code

You can find the code here.