Skip to content

Use Your Stablecoin for Fees

Enable users to pay transaction fees using your stablecoin. Tempo supports flexible fee payment options, allowing users to pay fees in any stablecoin they hold.

Demo

Use Your Stablecoin for Fees

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
Mint 100 pathUSD of Fee Liquidity for your token.
7
Send 100 AlphaUSD and pay fees in your token.
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/issuance

Steps

Create your stablecoin

First, create and mint your stablecoin by following the Create a Stablecoin guide.

Add fee pool liquidity

Before users can pay fees with your token, ensure there is sufficient liquidity in the fee pool. On the Andantino testnet, all validators expect fees in AlphaUSD, so you need to add AlphaUSD liquidity to your token's fee pool.

Add liquidity to your token's fee pool:

TypeScript
import { Hooks } from 'tempo.ts/wagmi'
import { parseUnits } from 'viem'
import { useConnection } from 'wagmi'
 
const { address } = useConnection()
const yourToken = '0x...' // Your issued token address
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD on testnet
 
const mintFeeLiquidity = Hooks.amm.useMintSync() 
 
// Add 100 AlphaUSD of liquidity to the fee pool 
mintFeeLiquidity.mutate({ 
  feeToken: validatorToken,
  to: address,
  userTokenAddress: yourToken,
  validatorTokenAddress: validatorToken,
  validatorTokenAmount: parseUnits('100', 6),
}) 

You can also check your token's fee pool liquidity at any time:

TypeScript
import { Hooks } from 'tempo.ts/wagmi'
 
const { data: pool } = Hooks.amm.usePool({
  userToken: yourToken,
  validatorToken: '0x20c0000000000000000000000000000000000001', // AlphaUSD on testnet
})
 
const hasLiquidity = pool && pool.reserveValidatorToken > 0n

If the pool has no liquidity (reserveValidatorToken == 0), you'll need to add liquidity to the fee pool before users can pay fees with your token. See the Create a Stablecoin guide for instructions on minting fee AMM liquidity.

Send payment with your token as fee

Your users can send payments using your issued stablecoin as the fee token:

PayWithIssuedToken.tsx
import React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
import { parseUnits, pad, stringToHex, isAddress } from 'viem'
 
export function PayWithIssuedToken() {
  const { address } = useConnection()
  const [recipient, setRecipient] = React.useState<string>('')
  const [memo, setMemo] = React.useState<string>('')
 
  const feeToken = '0x...' // Your issued token address
  const paymentToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
 
  const { data: paymentBalance, refetch: paymentBalanceRefetch } =
    Hooks.token.useGetBalance({ 
      account: address, 
      token: paymentToken, 
    }) 
 
  const { data: feeTokenBalance, refetch: feeTokenBalanceRefetch } =
    Hooks.token.useGetBalance({ 
      account: address, 
      token: feeToken, 
    }) 
 
  const sendPayment = Hooks.token.useTransferSync({ 
    mutation: { 
      onSettled() { 
        paymentBalanceRefetch() 
        feeTokenBalanceRefetch() 
      }, 
    }, 
  }) 
 
  const isValidRecipient = recipient && isAddress(recipient)
 
  const handleTransfer = () => { 
    if (!isValidRecipient) return
    sendPayment.mutate({ 
      amount: parseUnits('100', 6), 
      to: recipient as `0x${string}`, 
      token: paymentToken, 
      memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined, 
      feeToken, // Pay fees with your issued token 
    }) 
  } 
 
  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 || !isValidRecipient || sendPayment.isPending}
        onClick={handleTransfer}
        type="button"
      > 
        {sendPayment.isPending ? 'Sending...' : 'Send'}
      </button> 
    </>
  )
}

Users can set your stablecoin as their default fee token at the account level, or specify it for individual transactions. Learn more about how users pay fees in different stablecoins.

How It Works

When users pay transaction fees with your stablecoin, Tempo's fee system automatically handles the conversion if validators prefer a different token. The Fee AMM ensures seamless fee payments across all supported stablecoins.

Users can select your stablecoin as their fee token through:

  • Account-level preference: Set as default for all transactions
  • Transaction-level preference: Specify for individual transactions
  • Automatic selection: When directly interacting with your token contract

Learn more about how users pay fees in different stablecoins and the complete fee token preference hierarchy.

Benefits

  • User convenience: Users can pay fees with the same token they're using
  • Liquidity: Encourages users to hold your stablecoin
  • Flexibility: Works seamlessly with Tempo's fee system

Best Practices

Monitor pool liquidity

Regularly check your token's fee pool reserves to ensure users can consistently pay fees with your stablecoin. Low liquidity can prevent transactions from being processed.

Maintain adequate reserves

Keep sufficient validator token reserves in your fee pool to handle expected transaction volume. Consider your user base size and typical transaction frequency when determining reserve levels.

Test before launch

Before promoting fee payments with your token, thoroughly test the flow on testnet:

  1. Add liquidity to the fee pool
  2. Verify users can set your token as their fee preference
  3. Execute test transactions with various gas costs
  4. Monitor that fee conversions work correctly

Next Steps