Tempo is a Layer 1 blockchain designed for stablecoin payments. Unlike Ethereum or Solana, there is no native gas token. Transaction fees are paid directly in stablecoins. This guide covers setting up a development environment, funding a wallet on Moderato (Tempo's testnet), and sending your first stablecoin transfer.
Prerequisites
- Node.js v18+ or Foundry installed
- A Transfa API key (sign up at app.transfa.com)
- Basic familiarity with EVM development
Connect to Moderato testnet
Moderato is Tempo's public testnet. Here are the network details:
| Parameter | Value |
|---|---|
| Network name | Moderato |
| Chain ID | 42431 |
| HTTP RPC | https://rpc.moderato.tempo.xyz |
| WebSocket RPC | wss://rpc.moderato.tempo.xyz |
| Block explorer | https://explore.tempo.xyz |
| Block time | ~0.5 seconds |
With Foundry
Foundry works out of the box with Tempo. Test your connection:
cast chain-id --rpc-url https://rpc.moderato.tempo.xyz
# Returns: 42431cast block-number --rpc-url https://rpc.moderato.tempo.xyzWith viem
Tempo has first-class support in viemA TypeScript interface for Ethereum and EVM-compatible chains, with Tempo-specific extensions at viem.sh/tempo. starting from v2.43.0:
import { createPublicClient, http } from "viem";
import { tempoTestnet } from "viem/chains";
const client = createPublicClient({
chain: tempoTestnet,
transport: http(),
});
const blockNumber = await client.getBlockNumber();
console.log("Current block:", blockNumber);Fund your wallet from the faucet
Tempo's testnet faucet is an RPC method. No web UI needed. Call it directly:
cast rpc tempo_fundAddress 0xYOUR_ADDRESS \
--rpc-url https://rpc.moderato.tempo.xyzThis funds your wallet with four test stablecoins:
| Token | Address |
|---|---|
| pathUSD | 0x20c0000000000000000000000000000000000000 |
| AlphaUSD | 0x20c0000000000000000000000000000000000001 |
| BetaUSD | 0x20c0000000000000000000000000000000000002 |
| ThetaUSD | 0x20c0000000000000000000000000000000000003 |
Verify your balance:
cast erc20 balance 0x20c0000000000000000000000000000000000001 \
0xYOUR_ADDRESS --rpc-url https://rpc.moderato.tempo.xyzA common gotcha: eth_getBalance returns a meaningless large number on Tempo since there's no native token. Use balanceOf() on TIP-20 token contracts instead.
Send a stablecoin transfer
TIP-20 tokens are EVM-compatible, so standard transfer() calls work. Here's a transfer of 10 AlphaUSD:
With Foundry
cast send 0x20c0000000000000000000000000000000000001 \
"transfer(address,uint256)" \
0xRECIPIENT_ADDRESS 10000000 \
--rpc-url https://rpc.moderato.tempo.xyz \
--private-key $PRIVATE_KEYNote the amount: 10000000 = 10.000000 AlphaUSD. All TIP-20Tempo's enshrined token standard. Unlike ERC-20 where decimals vary, every TIP-20 token uses exactly 6 decimals. tokens use 6 decimals.
With viem
import { createWalletClient, http, parseUnits } from "viem";
import { tempoTestnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({
account,
chain: tempoTestnet,
transport: http(),
});
const hash = await walletClient.sendTransaction({
to: "0x20c0000000000000000000000000000000000001",
data: encodeFunctionData({
abi: [
{
name: "transfer",
type: "function",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
],
functionName: "transfer",
args: ["0xRECIPIENT_ADDRESS", parseUnits("10", 6)],
}),
});
console.log("Transaction hash:", hash);Attach a memo to a transfer
Tempo supports structured memos at the protocol level, useful for invoice numbers, payment references, or any identifier you need for reconciliation. This is a TIP-20 extension not available in standard ERC-20.
cast send 0x20c0000000000000000000000000000000000001 \
"transferWithMemo(address,uint256,bytes32)" \
0xRECIPIENT_ADDRESS 10000000 \
$(cast to-bytes32 "INV-2026-0042") \
--rpc-url https://rpc.moderato.tempo.xyz \
--private-key $PRIVATE_KEYThe memo field is a fixed bytes32 value. The TransferWithMemo event indexes the memo, so you can filter transfer logs by invoice number.
Verify the transfer with Transfa's Data API
Once a transfer is confirmed, you can query it through the Transfa Data API instead of parsing raw logs:
curl -X GET "https://api.transfa.com/v1/wallets/0xRECIPIENT_ADDRESS/transfers?chain=moderato" \
-H "x-api-key: YOUR_API_KEY"{
"data": [
{
"from": "0xSENDER_ADDRESS",
"to": "0xRECIPIENT_ADDRESS",
"tokenAddress": "0x20c0000000000000000000000000000000000001",
"amount": "10000000",
"balanceBefore": "0",
"balanceAfter": "10000000",
"blockTimestamp": 1707523200,
"transactionHash": "0xabc...",
"direction": "credit"
}
]
}The balanceBefore and balanceAfter fields are unique to Transfa's indexed data. They're not available from raw RPC calls or generic indexers.
Key differences from Ethereum development
A few things to know:
- No native token. Fees are paid in stablecoins.
eth_getBalanceis meaningless. UsebalanceOf()on TIP-20 contracts. - Higher state creation costs. New storage slots cost 250,000 gas (vs 20,000 on Ethereum). Account creation costs 250,000 gas. Contract deployment costs 1,000 gas per byte (vs 200). This is intentional; see TIP-1000Tempo's gas cost schedule that increases state creation costs to discourage state bloat on a payments-focused chain..
- Sub-second finality. Blocks finalize in ~0.5 seconds with no reorgs. You don't need to wait for multiple confirmations.
- Payment lanes. TIP-20 transfers get dedicated blockspace. Payment transactions are never crowded out by general EVM execution, even during congestion.
What to read next
- How to Track Wallet Balances and Transfers on Tempo: query indexed on-chain data without running your own indexer
- How to Sponsor Transaction Fees on Tempo: pay gas fees on behalf of your users
- Transfa Data API reference: full endpoint documentation