Skip to content

Mint Stablecoins

Create new tokens by minting them to a specified address. Minting increases the total supply of your stablecoin.

Steps

Create a Stablecoin

Before you can mint tokens, you need to create a stablecoin. Follow the Create a Stablecoin guide to deploy your token.

Once you've created your token, you can proceed to grant the issuer role and mint tokens.

Grant the Issuer Role

Assign the issuer role to the address that will mint tokens. Minting requires the ISSUER_ROLE.

Grant Issuer Role

demo
1
Create an account, or use an existing one.
2
Add testnet funds to your account.
3
Create & deploy a token to testnet.
4
Grant issuer role on token.
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/issuance
GrantIssuerRole.tsx
import React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useQueryClient } from '@tanstack/react-query'
 
export function GrantIssuerRole() {
  const queryClient = useQueryClient()
  const tokenAddress = '0x...' // Your token address
  const issuerAddress = '0x...' // Address to grant the issuer role
 
  const grant = Hooks.token.useGrantRolesSync({ 
    mutation: { 
      onSettled() { 
        queryClient.refetchQueries({ queryKey: ['hasRole'] }) 
      }, 
    }, 
  }) 
 
  const handleGrantIssuer = async () => { 
    await grant.mutate({ 
      token: tokenAddress, 
      roles: ['issuer'], 
      to: issuerAddress, 
      feeToken: '0x20c0000000000000000000000000000000000001', 
    }) 
  } 
 
  return (
    <button
      disabled={grant.isPending}
      onClick={handleGrantIssuer}
      type="button"
    > 
      {grant.isPending ? 'Granting...' : 'Grant Issuer Role'}
    </button> 
  )
}

Mint Tokens to a Recipient

Now that the issuer role is granted, you can mint tokens to any address.

Mint Tokens

demo
1
Create an account, or use an existing one.
2
Add testnet funds to your account.
3
Create & deploy a token to testnet.
4
Grant issuer role on token.
5
Mint 100 tokens to yourself.
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/issuance
MintToken.tsx
import React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
import { parseUnits, pad, stringToHex } from 'viem'
import { useQueryClient } from '@tanstack/react-query'
 
export function MintToken() {
  const { address } = useConnection()
  const queryClient = useQueryClient()
  const tokenAddress = '0x...' // Your token address
  const [recipient, setRecipient] = React.useState<string>('')
  const [memo, setMemo] = React.useState<string>('')
 
  const { data: metadata } = Hooks.token.useGetMetadata({ 
    token: tokenAddress, 
  }) 
 
  const mint = Hooks.token.useMintSync({ 
    mutation: { 
      onSettled() { 
        queryClient.refetchQueries({ queryKey: ['getBalance'] }) 
      }, 
    }, 
  }) 
 
  const handleMint = () => { 
    if (!tokenAddress || !recipient || !metadata) return
    mint.mutate({ 
      amount: parseUnits('100', metadata.decimals), 
      to: recipient as `0x${string}`, 
      token: tokenAddress, 
      memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined, 
      feeToken: '0x20c0000000000000000000000000000000000001', 
    }) 
  } 
 
  return (
    <>
      <div>
        <label>Recipient address</label>
        <input
          type="text"
          value={recipient}
          onChange={(e) => setRecipient(e.target.value)}
          placeholder="0x..."
        />
      </div>
      <div>
        <label>Memo (optional)</label>
        <input
          type="text"
          value={memo}
          onChange={(e) => setMemo(e.target.value)}
          placeholder="INV-12345"
        />
      </div>
      <button
        disabled={!address || mint.isPending}
        onClick={handleMint}
        type="button"
      > 
        {mint.isPending ? 'Minting...' : 'Mint'}
      </button> 
    </>
  )
}

Recipes

Burning Stablecoins

To decrease supply, you can burn tokens from your own balance. Burning requires the ISSUER_ROLE and sufficient balance in the caller's account.

Burn Your Token

demo
1
Create an account, or use an existing one.
2
Add testnet funds to your account.
3
Create & deploy a token to testnet.
4
Grant issuer role on token.
5
Mint 100 tokens to yourself.
6
Burn 100 tokens from yourself.
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/issuance
BurnToken.tsx
import React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
import { parseUnits, pad, stringToHex } from 'viem'
import { useQueryClient } from '@tanstack/react-query'
 
export function BurnToken() {
  const { address } = useConnection()
  const queryClient = useQueryClient()
  const tokenAddress = '0x...' // Your token address
  const [memo, setMemo] = React.useState<string>('')
 
  const { data: metadata } = Hooks.token.useGetMetadata({ 
    token: tokenAddress, 
  }) 
 
  const burn = Hooks.token.useBurnSync({ 
    mutation: { 
      onSettled() { 
        queryClient.refetchQueries({ queryKey: ['getBalance'] }) 
      }, 
    }, 
  }) 
 
  const handleBurn = () => { 
    if (!tokenAddress || !address || !metadata) return
    burn.mutate({ 
      amount: parseUnits('100', metadata.decimals), 
      token: tokenAddress, 
      memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined, 
      feeToken: '0x20c0000000000000000000000000000000000001', 
    }) 
  } 
 
  return (
    <>
      <div>
        <label>Memo (optional)</label>
        <input
          type="text"
          value={memo}
          onChange={(e) => setMemo(e.target.value)}
          placeholder="INV-12345"
        />
      </div>
      <button
        disabled={!address || burn.isPending}
        onClick={handleBurn}
        type="button"
      > 
        {burn.isPending ? 'Burning...' : 'Burn'}
      </button> 
    </>
  )
}

Best Practices

Monitor Supply Caps

If your token has a supply cap set, any mint() or mintWithMemo() call that would exceed the cap will revert with SupplyCapExceeded(). You must either:

  • Burn tokens to reduce total supply below the cap
  • Increase the supply cap (requires DEFAULT_ADMIN_ROLE)
  • Remove the cap entirely by setting it to type(uint256).max

Use getMetadata to check your token's total supply before minting.

Role Separation

Assign the issuer role to dedicated treasury or minting addresses separate from your admin address. This enhances security by limiting the privileges of any single address.

Learning Resources