Send a Payment
Send stablecoin payments between accounts on Tempo. Payments can include optional memos for reconciliation and tracking.
Demo
By the end of this guide you will be able to send payments on Tempo with an optional memo.
Send a Payment
demoSteps
Set up Wagmi & integrate accounts
Ensure that you have set up your project with Wagmi and integrated accounts by following either of the guides:
Add testnet funds¹
Before you can send a payment, you need to fund your account. In this guide you will be sending AlphaUSD (0x20c000…0001).
The built-in Tempo testnet faucet funds accounts with AlphaUSD.
Add Funds
import { Hooks } from 'tempo.ts/wagmi'
import { useConnection } from 'wagmi'
function AddFunds() {
const { address } = useConnection()
const { mutate, isPending } = Hooks.faucet.useFundSync()
return (
<button onClick={() => mutate({ account: address })} disabled={isPending}>
Add Funds
</button>
)
}Add send payment logic
Now that you have AlphaUSD you are ready to add logic to send a payment with an optional memo.
Send Payment
import { Hooks } from 'tempo.ts/wagmi'
import { parseUnits, stringToHex, pad } from 'viem'
function SendPaymentWithMemo() {
const sendPayment = Hooks.token.useTransferSync()
return (
<form onSubmit={
(event) => {
event.preventDefault()
const formData = new FormData(event.target as HTMLFormElement)
const recipient = (formData.get('recipient') ||
'0x0000000000000000000000000000000000000000') as `0x${string}`
const memo = (formData.get('memo') || '') as string
sendPayment.mutate({
amount: parseUnits('100', 6),
to: recipient,
token: '0x20c0000000000000000000000000000000000001',
memo: memo ? pad(stringToHex(memo), { size: 32 }) : undefined,
})
}
}>
<div>
<label htmlFor="recipient">Recipient address</label>
<input type="text" name="recipient" placeholder="0x..." />
</div>
<div>
<label htmlFor="memo">Memo (optional)</label>
<input type="text" name="memo" placeholder="Optional memo" />
</div>
<button
type="submit"
disabled={sendPayment.isPending}
>
Send Payment
</button>
</form>
)
}Display receipt
Now that you can send a payment, you can display the transaction receipt on success.
import { Hooks } from 'tempo.ts/wagmi'
import { parseUnits, stringToHex, pad } from 'viem'
function SendPaymentWithMemo() {
const sendPayment = Hooks.token.useTransferSync()
return (
<>
{/* ... your payment form ... */}
{sendPayment.data && (
<a href={`https://explore.tempo.xyz/tx/${sendPayment.data.receipt.transactionHash}`}>
View receipt
</a>
)}
</>
)
}Next steps
Now that you have made a payment you can
- Accept a payment to receive payments in your application
- Learn about Batch Transactions
- Send a payment with a specific fee token
Recipes
Basic transfer
Send a payment using the standard transfer function:
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.transferSync({
amount: parseUnits('100', 6), // 100 tokens (6 decimals)
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000001', // AlphaUSD
})Transfer with memo
Include a memo for payment reconciliation and tracking:
import { parseUnits } from 'viem'
import { client } from './viem.config'
const invoiceId = pad(stringToHex('INV-12345'), { size: 32 })
const { receipt } = await client.token.transferSync({
amount: parseUnits('100', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000001',
memo: invoiceId,
})The memo is a 32-byte value that can store payment references, invoice IDs, order numbers, or any other metadata.
Using Solidity
If you're building a smart contract that sends payments:
interface ITIP20 {
function transfer(address to, uint256 amount) external returns (bool);
function transferWithMemo(address to, uint256 amount, bytes32 memo) external;
}
contract PaymentSender {
ITIP20 public token;
function sendPayment(address recipient, uint256 amount) external {
token.transfer(recipient, amount);
}
function sendPaymentWithMemo(
address recipient,
uint256 amount,
bytes32 invoiceId
) external {
token.transferWithMemo(recipient, amount, invoiceId);
}
}Batch payment transactions
Send multiple payments in a single transaction using batch transactions:
import { encodeFunctionData, parseUnits } from 'viem'
import { Abis } from 'tempo.ts/viem'
import { client } from './viem.config'
const tokenABI = Abis.tip20
const recipient1 = '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb'
const recipient2 = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'
const calls = [
{
to: '0x20c0000000000000000000000000000000000001', // AlphaUSD address
data: encodeFunctionData({
abi: tokenABI,
functionName: 'transfer',
args: [recipient1, parseUnits('100', 6)],
}),
},
{
to: '0x20c0000000000000000000000000000000000001',
data: encodeFunctionData({
abi: tokenABI,
functionName: 'transfer',
args: [recipient2, parseUnits('50', 6)],
}),
},
]
const hash = await client.sendTransaction({ calls })Payment events
When you send a payment, the token contract emits events:
- Transfer: Standard ERC-20 transfer event
- TransferWithMemo: Additional event with memo (if using
transferWithMemo)
You can filter these events to track payments in your off-chain systems.
Best practices
Loading state
Users should see a loading state when the payment is being processed.
You can use the isPending property from the useTransferSync hook to show pending state to the user.
Error handling
If an error unexpectedly occurs, you can display an error message to the user by using the error property from the useTransferSync hook.
import { Hooks } from 'tempo.ts/wagmi'
function SendPayment() {
const sendPayment = Hooks.token.useTransferSync()
return (
<>
{/* ... your paymentform ... */}
{sendPayment.error && <div>Error: {sendPayment.error.message}</div>}
</>
)
}