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
demoSteps
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.
import { , } from 'viem'
import { } from 'viem/accounts'
import { } from 'viem/chains'
const = ({
: .({
: '0x20c0000000000000000000000000000000000001',
}),
: (),
})
const = Handler.feePayer({
: ('0x...'),
,
})
const = createServer(.listener)
.listen(3000)Configure your client to use the fee payer service
Use the withFeePayer transport provided by Viem (link). It routes transactions to the configured fee payer service for sponsorship when feePayer: true is requested on a transaction.
import { } from 'viem/chains'
import { } from 'viem/tempo'
import { , } from 'wagmi'
import { , } from 'wagmi/tempo'
export const = ({
: [
({
: .('https://keys.tempo.xyz'),
}),
],
: [],
: false,
: {
[.]: ((), ('https://sponsor.moderato.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.
import { } from 'wagmi/tempo'
import { } from 'viem'
import { } from 'viem/accounts'
const = '0x20c0000000000000000000000000000000000001'
function () {
const = ('0x...')
const = ..()
const = ..({
: ,
})
return (
< ={
() => {
.()
const = new (. as HTMLFormElement)
const = (.('recipient') ||
'0x0000000000000000000000000000000000000000') as `0x${string}`
.({
: ('100', ..),
: true,
: ,
: ,
})
}
}>
<>
< ="recipient"> Recipient address </>
< ="text" ="0x..." />
</>
< ="submit" ={.}>
Send Payment
</>
</>
)
}Next Steps
Now that you've implemented fee sponsorship, you can:
- Learn more about the Tempo Transaction type and fee payer signature details
- Explore Batch Transactions to sponsor multiple operations at once
- Learn how to Pay Fees in Any Stablecoin
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.
import { , } from 'viem'
import { } from 'viem/accounts'
import { } from 'viem/chains'
const = ({
: ,
: (),
})
const { } = await .token.transferSync({
: parseUnits('10.5', 6),
: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
: '0x20c0000000000000000000000000000000000000',
: ('0x...'),
})Best practices
- Set sponsorship limits: Implement daily or per-user limits to control costs
- Monitor expenses: Track sponsorship costs regularly to stay within budget
- Consider selective sponsorship: Only sponsor fees for specific operations or user segments
- 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
Signing Hash Behavior
When building fee-sponsored transactions, the sender must indicate sponsorship before signing. This is because the transaction's signing hash differs based on whether it will be sponsored:
- Sponsored transactions: The
fee_tokenfield is omitted from the sender's signing payload, and a0x00marker is used. This allows the fee payer to choose the fee token. - Non-sponsored transactions: The
fee_tokenis included in the sender's signing payload.
The withFeePayer transport and feePayer: true parameter handle this automatically. If you're building transactions manually with a local account as fee payer, the Viem SDK handles this for you:
import { , , } from 'viem'
import { } from 'viem/accounts'
import { } from 'viem/chains'
const = ({
: ,
: (),
})
const = ('0x...')
const = ('0x...')
// When feePayer is an Account object, Viem:
// 1. Has the sender sign the transaction (with feeToken)
// 2. Recovers the sender address from their signature
// 3. Has the fee payer sign a separate hash (includes sender + feeToken)
// 4. Serializes the dual-signed transaction
const { } = await .token.transferSync({
: ,
: ('10.5', 6),
: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
: '0x20c0000000000000000000000000000000000000',
: ,
})Learning Resources
Learn more about fees and how they work on Tempo
Technical specification for TempoTransactions and fee payer signature details
Learn how to sponsor fees for multiple operations at once
Understand fee token selection and how to pay with different stablecoins