Managing Fee Liquidity
The Fee AMM converts transaction fees between stablecoins when users pay in a different token than the validator prefers. This guide shows you how to add and remove liquidity to enable fee conversions.
Manage Fee Liquidity
demoSteps
Check pool reserves
Before adding liquidity, check the current pool reserves to understand the pool state.
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits } from 'viem'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function ManageFeeLiquidity() {
const { data: pool } = Hooks.amm.usePool({
userToken,
validatorToken,
})
return (
<div>
<div>User token reserves: {formatUnits(pool?.reserveUserToken ?? 0n, 6)}</div>
<div>Validator token reserves: {formatUnits(pool?.reserveValidatorToken ?? 0n, 6)}</div>
</div>
)
}Add liquidity
Add validator token to the pool to receive LP tokens representing your share. The first liquidity provider to a new pool must burn 1,000 units of liquidity. This costs approximately 0.002 USD and prevents attacks on pool reserves. Learn more in the Fee AMM specification.
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useConnection } from 'wagmi'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function ManageFeeLiquidity() {
const { address } = useConnection()
const { data: pool } = Hooks.amm.usePool({
userToken,
validatorToken,
})
const mintLiquidity = Hooks.amm.useMintSync()
return (
<div>
<div>User token reserves: {formatUnits(pool?.reserveUserToken ?? 0n, 6)}</div>
<div>Validator token reserves: {formatUnits(pool?.reserveValidatorToken ?? 0n, 6)}</div>
<button type="button" onClick={() => {
if (!address) return
mintLiquidity.mutate({
userTokenAddress: userToken,
validatorTokenAddress: validatorToken,
validatorTokenAmount: parseUnits('100', 6),
to: address,
feeToken: validatorToken,
})
}}>
Add Liquidity
</button>
</div>
)
}Check your LP balance
View your LP token balance to see your share of the pool.
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useConnection } from 'wagmi'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function ManageFeeLiquidity() {
const { address } = useConnection()
const { data: pool } = Hooks.amm.usePool({
userToken,
validatorToken,
})
const { data: balance } = Hooks.amm.useLiquidityBalance({
address,
userToken,
validatorToken,
})
const mintLiquidity = Hooks.amm.useMintSync()
return (
<div>
<div>LP token balance: {formatUnits(balance ?? 0n, 6)}</div>
<div>User token reserves: {formatUnits(pool?.reserveUserToken ?? 0n, 6)}</div>
<div>Validator token reserves: {formatUnits(pool?.reserveValidatorToken ?? 0n, 6)}</div>
<button type="button" onClick={() => {
if (!address) return
mintLiquidity.mutate({
userTokenAddress: userToken,
validatorTokenAddress: validatorToken,
validatorTokenAmount: parseUnits('100', 6),
to: address,
feeToken: validatorToken,
})
}}>
Add Liquidity
</button>
</div>
)
}Remove liquidity
Burn LP tokens to withdraw your share of pool reserves plus accumulated fees.
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useConnection } from 'wagmi'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function ManageFeeLiquidity() {
const { address } = useConnection()
const { data: pool } = Hooks.amm.usePool({
userToken,
validatorToken,
})
const { data: balance } = Hooks.amm.useLiquidityBalance({
address,
userToken,
validatorToken,
})
const mintLiquidity = Hooks.amm.useMintSync()
const burnLiquidity = Hooks.amm.useBurnSync()
return (
<div>
<div>LP token balance: {formatUnits(balance ?? 0n, 6)}</div>
<div>User token reserves: {formatUnits(pool?.reserveUserToken ?? 0n, 6)}</div>
<div>Validator token reserves: {formatUnits(pool?.reserveValidatorToken ?? 0n, 6)}</div>
<button type="button" onClick={() => {
if (!address) return
mintLiquidity.mutate({
userTokenAddress: userToken,
validatorTokenAddress: validatorToken,
validatorTokenAmount: parseUnits('100', 6),
to: address,
feeToken: validatorToken,
})
}}>
Add Liquidity
</button>
<button type="button" onClick={() => {
if (!address) return
burnLiquidity.mutate({
userToken,
validatorToken,
liquidity: parseUnits('10', 6), // Burn 10 LP tokens
to: address,
})
}}>
Remove Liquidity
</button>
</div>
)
}Recipes
Monitor pool utilization
Track fee swap activity to understand pool utilization and revenue.
import * as React from 'react'
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits } from 'viem'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function MonitorSwaps() {
const [swaps, setSwaps] = React.useState<any[]>([])
Hooks.amm.useWatchFeeSwap({
userToken,
validatorToken,
onLogs(logs) {
for (const log of logs) {
setSwaps((prev) => [...prev, {
amountIn: formatUnits(log.args.amountIn, 6),
amountOut: formatUnits(log.args.amountOut, 6),
revenue: formatUnits(log.args.amountIn * 30n / 10000n, 6),
}])
}
},
})
return (
<div>
{swaps.map((swap, i) => (
<div key={i}>
Swap: {swap.amountIn} → {swap.amountOut} (LP revenue: {swap.revenue})
</div>
))}
</div>
)
}Rebalance pools
You can rebalance pools by swapping validator tokens for accumulated user tokens at a fixed rate. Rebalancing restores validator token reserves and enables continued fee conversions. Learn more here.
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useConnection } from 'wagmi'
const userToken = '0x20c0000000000000000000000000000000000002' // BetaUSD
const validatorToken = '0x20c0000000000000000000000000000000000001' // AlphaUSD
function RebalancePool() {
const { address } = useConnection()
const { data: pool } = Hooks.amm.usePool({
userToken,
validatorToken,
})
const rebalance = Hooks.amm.useRebalanceSwapSync()
return (
<div>
<div>User token reserves: {formatUnits(pool?.reserveUserToken ?? 0n, 6)}</div>
<div>Validator token reserves: {formatUnits(pool?.reserveValidatorToken ?? 0n, 6)}</div>
<button type="button" onClick={() => {
if (!address || !pool) return
// Swap validator token for user token at 0.9985 rate
rebalance.mutate({
userToken,
validatorToken,
amountOut: pool.reserveUserToken, // Amount of user token to receive
to: address,
})
}}>
Rebalance
</button>
</div>
)
}Best Practices
Monitor pool reserves
Regularly check pool reserves to ensure sufficient liquidity for fee conversions. Low reserves can prevent transactions from being processed.
Add liquidity when:
- Transaction rates increase for a given
userToken - Reserve levels drop below expected daily volume
- Multiple validators begin preferring the same token
Maintain adequate reserves
As an issuer, keep sufficient validator token reserves to handle expected transaction volume. Consider your anticipated fee conversion volume when determining reserve levels.
For new token pairs, provide the entire initial amount in the validator token. The pool naturally accumulates user tokens as fees are paid.
Deploy liquidity strategically
Focus liquidity on pools with:
- High transaction volume and frequent fee conversions
- New stablecoins that need initial bootstrapping
- Validator tokens preferred by multiple validators