Skip to content

Sponsor User Fees

Enable gasless transactions by sponsoring transaction fees for your users. Tempo's native fee sponsorship allows applications to pay fees on behalf of users, improving UX and removing friction from payment flows.

Demo

Sponsor User Fees

demo
1
Create an account, or use an existing one.
2
Add testnet funds to your account.
3
Send 100 AlphaUSD with fees sponsored by the testnet fee payer.
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/payments

Steps

Set up the fee payer service

You can stand up a minimal fee payer service using the Handler.feePayer handler provided by the Tempo TypeScript SDK (link). To sponsor transactions, you need a funded account that will act as the fee payer.

server.ts
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempo } from 'tempo.ts/chains'
import { Handler } from 'tempo.ts/server'
 
const client = createClient({
  chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
  transport: http(),
})
 
const handler = Handler.feePayer({ 
  account: privateKeyToAccount('0x...'), 
  client, 
}) 
 
const server = createServer(handler.listener)
server.listen(3000)

Configure your client to use the fee payer service

Use the withFeePayer transport provided by the TypeScript SDK (link). It routes transactions to the configured fee payer service for sponsorship when feePayer: true is requested on a transaction.

wagmi.config.ts
import { tempo } from 'tempo.ts/chains'
import { withFeePayer } from 'tempo.ts/viem'
import { KeyManager, webAuthn } from 'tempo.ts/wagmi'
import { createConfig, http } from 'wagmi'
 
export const config = createConfig({
  connectors: [
    webAuthn({
      keyManager: KeyManager.localStorage(),
    }),
  ],
  chains: [tempo({ feeToken: '0x20c0000000000000000000000000000000000001' })],
  multiInjectedProviderDiscovery: false,
  transports: {
    [tempo.id]: withFeePayer(http(), http('https://sponsor.testnet.tempo.xyz')),
  },
})

Sponsor your user's transactions

Now you can sponsor transactions by passing feePayer: true in the transaction parameters. For more details on how to send a transaction, see the Send a payment guide.

SendSponsoredPayment.tsx
import { Hooks } from 'tempo.ts/wagmi'
import { parseUnits } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
 
function SendSponsoredPayment() {
  const sponsorAccount = privateKeyToAccount('0x...')
  const sendPayment = Hooks.token.useTransferSync() 
  const metadata = Hooks.token.useGetMetadata({
    token: alphaUsd,
  })
 
  return (
    <form onSubmit={
      (event) => {
        event.preventDefault()
        const formData = new FormData(event.target as HTMLFormElement)
 
        const recipient = (formData.get('recipient') ||
          '0x0000000000000000000000000000000000000000') as `0x${string}`
 
        sendPayment.mutate({ 
          amount: parseUnits('100', metadata.data.decimals), 
          feePayer: true, 
          to: recipient, 
          token: alphaUsd, 
        }) 
      }
    }>
      <div>
        <label htmlFor="recipient"> Recipient address </label>
        <input type="text" placeholder="0x..." />
      </div>
      <button type="submit" disabled={sendPayment.isPending}>
        Send Payment
      </button>
    </form>
  )
}

Next Steps

Now that you've implemented fee sponsorship, you can:

Recipes

Local account sponsorship

The example above uses a fee payer server to sign and sponsor transactions. If you want to sponsor transactions locally, you can easily do so by passing a local account to the feePayer parameter.

client.ts
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempo } from 'tempo.ts/chains'
 
const client = createClient({
  chain: tempo({ feeToken: '0x20c0000000000000000000000000000000000001' }),
  transport: http(),
})
 
const { receipt } = await client.token.transferSync({
  amount: parseUnits('10.5', 6),
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
  token: '0x20c0000000000000000000000000000000000000',
  feePayer: privateKeyToAccount('0x...'), 
})

:::

Best practices

  1. Set sponsorship limits: Implement daily or per-user limits to control costs
  2. Monitor expenses: Track sponsorship costs regularly to stay within budget
  3. Consider selective sponsorship: Only sponsor fees for specific operations or user segments
  4. Educate users: Clearly communicate when fees are being sponsored

Security Considerations

  • Transaction-specific: Fee payer signatures are tied to specific transactions
  • No delegation risk: Fee payer can't execute arbitrary transactions
  • Balance checks: Network verifies fee payer has sufficient balance
  • Signature validation: Both signatures must be valid

Learning Resources