·Transfa Team

How to Get Started Building on Tempo

Set up your development environment for Tempo, fund a testnet wallet, and send your first stablecoin transfer on Moderato.

tempogetting-startedtestnetmoderato

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

Connect to Moderato testnet

Moderato is Tempo's public testnet. Here are the network details:

ParameterValue
Network nameModerato
Chain ID42431
HTTP RPChttps://rpc.moderato.tempo.xyz
WebSocket RPCwss://rpc.moderato.tempo.xyz
Block explorerhttps://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: 42431
cast block-number --rpc-url https://rpc.moderato.tempo.xyz

With viem

Tempo has first-class support in viem 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.xyz

This funds your wallet with four test stablecoins:

TokenAddress
pathUSD0x20c0000000000000000000000000000000000000
AlphaUSD0x20c0000000000000000000000000000000000001
BetaUSD0x20c0000000000000000000000000000000000002
ThetaUSD0x20c0000000000000000000000000000000000003

Verify your balance:

cast erc20 balance 0x20c0000000000000000000000000000000000001 \
  0xYOUR_ADDRESS --rpc-url https://rpc.moderato.tempo.xyz

A 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_KEY

Note the amount: 10000000 = 10.000000 AlphaUSD. All TIP-20 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_KEY

The 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_getBalance is meaningless. Use balanceOf() 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-1000.
  • 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