Back to home

ThaiFi Documentation

Complete guide for interacting with ThaiFi using Foundry Cast. Learn how to query blocks, transactions, tokens, deploy contracts, and manage fees.

Download SKILL.md for AI agents

A ready-to-use skill file for vibe-coding agents (Claude Code, Cursor, etc.) — drop it into your project to give the agent full ThaiFi context.

Network Information

Chain ID
17
Block Time
0.5s
Max Throughput
~100,000 TPS
Consensus
Simplex BFT with DKG
RPC Endpoint
https://rpc.thaifi.com

Table of Contents

01. Install Foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. castis Foundry's command-line tool for interacting with EVM smart contracts, sending transactions, and getting chain data.

Install via foundryup

Bash — macOS / Linux
curl -L https://getfoundry.sh/install | bash

After installation, restart your terminal and run:

Bash
foundryup

Verify Installation

Bash
cast --version

02. Gas Fee Model

Important: ThaiFi has no volatile native gas token. Fees are paid in TIP-20 stablecoins — not native ETH.

Because fees are paid in a stablecoin, you must hold a fee token balance (e.g. pathUSD) — not native ETH — to transact.

03. Setup

Common Variables

Bash
# RPC endpoint
RPC=https://rpc.thaifi.com

# Token & system addresses
pathUSD=0x20C0000000000000000000000000000000000000
TIP20_FACTORY=0x20fc000000000000000000000000000000000000
FEE_MANAGER=0xfeEC000000000000000000000000000000000000
STABLECOIN_DEX=0xdec0000000000000000000000000000000000000

# Private key (store as env variable)
export PRIVATE_KEY=<your_private_key>

Predeployed System Contracts

AddressNamePurpose
0x20C0...0000pathUSDFirst stablecoin (default fee token)
0x20fc...0000TIP-20 FactoryCreate new TIP-20 tokens
0xfeEC...0000Fee ManagerFee payments, Fee AMM & fee token settings
0xdec0...0000Stablecoin DEXEnshrined DEX for stablecoin swaps
0x403c...0000TIP-403 RegistryTransfer policy registry
0xcA11...CA11Multicall3Batch multiple calls
0xba5E...a5EdCreateXDeterministic CREATE2 deployment
0x0000...8ba3Permit2Token approvals & transfers

04. TIP-20 Token Standard

TIP-20 extends ERC-20 with payment-native features:

05. Create a TIP-20 Token

Call createToken on the TIP-20 Factory:

Bash
cast send 0x20fc000000000000000000000000000000000000 \
  "createToken(string,string,string,address,address,bytes32)" \
  "My USD Coin" "MUSD" "USD" \
  0x20C0000000000000000000000000000000000000 \
  $YOUR_ADDRESS \
  0x0000000000000000000000000000000000000000000000000000000000000000 \
  --rpc-url https://rpc.thaifi.com \
  --private-key $PRIVATE_KEY

Args: name, symbol, currency, quoteToken, admin, salt. The quoteToken must be pathUSD (0x20C0...0000) — passing address(0) reverts with InvalidQuoteToken.

The factory deploys the token deterministically from salt + admin — same wallet with the same salt reverts TokenAlreadyExists; bump the salt for each new token. The caller gets all roles (issuer/pause/etc.). The new token's address is in topics[1] of the TokenCreated event (zero-padded — take the last 40 hex chars).

Bash — read token address from the event
TOPIC=$(cast logs --address 0x20fc000000000000000000000000000000000000 \
  --from-block latest \
  "TokenCreated(address,string,string,string,address,address,bytes32)" \
  --rpc-url https://rpc.thaifi.com \
  | grep -oE '0x0{24}[0-9a-fA-F]{40}' | head -1)
TOKEN="0x${TOPIC:26}"
echo "Token address: $TOKEN"

06. View Token Info

Bash
# View all token info at once
echo "Name:         $(cast call $pathUSD 'name()(string)' --rpc-url $RPC)"
echo "Symbol:       $(cast call $pathUSD 'symbol()(string)' --rpc-url $RPC)"
echo "Currency:     $(cast call $pathUSD 'currency()(string)' --rpc-url $RPC)"
echo "Decimals:     $(cast call $pathUSD 'decimals()(uint8)' --rpc-url $RPC)"
echo "Total Supply: $(cast call $pathUSD 'totalSupply()(uint256)' --rpc-url $RPC)"

Note: TIP-20 tokens always use 6 decimals (THAIFI-TIP21)

07. View Balance

Bash
cast call $pathUSD "balanceOf(address)(uint256)" $ADMIN --rpc-url $RPC

Conversion Table (6 decimals)

AmountRaw Value
1 pathUSD1000000
10 pathUSD10000000
100 pathUSD100000000
1,000 pathUSD1000000000
10,000 pathUSD10000000000

08. Mint Token

Note: You must have ISSUER_ROLE to mint tokens.

Bash
# Mint 100 pathUSD (100 * 10^6 = 100000000)
cast send $pathUSD \
  "mint(address,uint256)" \
  $RECIPIENT 100000000 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC

09. Transfer Token

Bash
# Transfer 1 pathUSD (1,000,000 units) to recipient
cast send $pathUSD \
  "transfer(address,uint256)(bool)" \
  $RECIPIENT 1000000 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC

10. Add Token to Fee AMM

To let users pay gas in your TIP-20 token, the Fee AMMneeds liquidity to convert it into the validator's fee token (pathUSD). The Fee AMM lives inside the Fee Manager precompile (0xfeec000000000000000000000000000000000000) — not the Stablecoin DEX (which is an orderbook for trading).

Symptom of missing liquidity: transactions from accounts whose fee token is your token revert with insufficient liquidity in FeeAMM pool to swap fee tokens — even for a simple transfer.

Step 1 — Approve both tokens for the Fee Manager

Bash
# Your token (example: 10 tokens, 6 decimals)
cast send <TOKEN_ADDRESS> "approve(address,uint256)" \
  0xfeec000000000000000000000000000000000000 10000000 \
  --rpc-url https://rpc.thaifi.com --private-key $PRIVATE_KEY

# pathUSD (validator token)
cast send 0x20C0000000000000000000000000000000000000 \
  "approve(address,uint256)" \
  0xfeec000000000000000000000000000000000000 10000000 \
  --rpc-url https://rpc.thaifi.com --private-key $PRIVATE_KEY

Step 2 — Mint Fee AMM liquidity

Bash
# mint(userToken, validatorToken, amountValidatorToken, to)
# You specify how much pathUSD to add; the AMM pairs it with your token (~1:1, both USD-stable).
cast send 0xfeec000000000000000000000000000000000000 \
  "mint(address,address,uint256,address)" \
  <TOKEN_ADDRESS> \
  0x20C0000000000000000000000000000000000000 \
  10000000 \
  $YOUR_ADDRESS \
  --rpc-url https://rpc.thaifi.com --private-key $PRIVATE_KEY

Step 3 — Verify pool reserves

Bash
cast call 0xfeec000000000000000000000000000000000000 \
  "getPool(address,address)(uint128,uint128)" \
  <TOKEN_ADDRESS> \
  0x20C0000000000000000000000000000000000000 \
  --rpc-url https://rpc.thaifi.com

How much liquidity? Fees are tiny (~0.0002 USD per tx), so a small pool goes a long way — 10 pathUSD covers tens of thousands of transactions. Users paying fees in your token push it into the pool and pathUSD flows out to validators, keeping the pool balanced automatically.

Optional: to also make your token tradeable, add orderbook liquidity on the Stablecoin DEX (createPair + place bid/ask orders) — that is a separate system from the Fee AMM.

11. Fee Manager

Fee Manager precompile is located at 0xfeEC000000000000000000000000000000000000

Fee Flow

User sends transaction
    │
    ▼
collect_fee_pre_tx  → Deduct gas fee from user
    │
    ▼
Transaction executes
    │
    ▼
collect_fee_post_tx → Accumulate to collected_fees[validator][token]
    │
    ▼
distributeFees()   → Transfer accumulated fees → validator address

Check Validator Fees

Bash
# Accumulated fees
cast call $FEE_MANAGER \
  "collectedFees(address,address)(uint256)" \
  $VALIDATOR $pathUSD --rpc-url $RPC

# Validator fee token
cast call $FEE_MANAGER \
  "validatorTokens(address)(address)" \
  $VALIDATOR --rpc-url $RPC

Distribute Fees

Bash
# Anyone can call — transfers accumulated fees to validator
cast send $FEE_MANAGER \
  "distributeFees(address,address)" \
  $VALIDATOR $pathUSD \
  --private-key $PRIVATE_KEY --rpc-url $RPC

12. Set Your Fee Token

Every account has a default fee token (initially pathUSD). If you hold a different TIP-20 stablecoin, you can switch your fee token to it — as long as the Fee AMM has liquidity for that token. This lets an account transact without ever holding pathUSD.

Check your current fee token

Bash
cast call 0xfeec000000000000000000000000000000000000 \
  "userTokens(address)(address)" \
  $YOUR_ADDRESS --rpc-url https://rpc.thaifi.com

Set your fee token

Bash
# Example: pay fees in your USD stablecoin
cast send 0xfeec000000000000000000000000000000000000 \
  "setUserToken(address)" \
  <TOKEN_ADDRESS> \
  --rpc-url https://rpc.thaifi.com --private-key $PRIVATE_KEY

Note: the setUserToken transaction itself pays fees in your current fee token. Brand-new accounts with zero fee-token balance need a sponsored first transaction (see Gas Sponsorship) or a small pathUSD top-up to get started.

13. Gas Sponsorship

ThaiFi supports Tempo's fee sponsorship model — a third party (fee payer) signs the feePayerSignatureso users don't need to hold fee tokens.

Client-side (viem)

TypeScript
import { Account, withRelay } from "viem/tempo";

const account = Account.fromSecp256k1(privateKey);
const client = createWalletClient({
  account,
  chain: thaifi,
  transport: withRelay(
    http("https://rpc.thaifi.com"),
    http("https://sponsor.thaifi.com"),
    { policy: "sign-and-broadcast" },
  ),
});

await client.sendTransaction({
  to, data, value,
  feePayer: true, // ← enables sponsorship
});

Self-hosted Fee Payer

Deploy the fee-payer worker (Cloudflare Worker + Hono) with:

Env
SPONSOR_PRIVATE_KEY=<sponsor_wallet_key>
TEMPO_ENV=thaifi
TEMPO_RPC_URL=https://rpc.thaifi.com

14. Deploy Smart Contracts

Deploy with forge create

Bash
forge create src/MyContract.sol:MyContract \
  --rpc-url https://rpc.thaifi.com \
  --private-key $PRIVATE_KEY \
  --constructor-args 0x20C0000000000000000000000000000000000000 \
  --gas-limit 10000000 --slow

Deploy with forge script

Bash
forge script script/Deploy.s.sol \
  --rpc-url https://rpc.thaifi.com \
  --broadcast \
  --private-key $PRIVATE_KEY \
  --slow

⚠️ Gas limit gotcha: forge script may run out of gas. Add --gas-limit 10000000 --skip-simulation or use forge create per contract.

UUPS Upgradeable Proxy (two-step)

Bash
# Step 1 — Deploy implementation
forge create src/MyContractV2.sol:MyContractV2 \
  --rpc-url https://rpc.thaifi.com \
  --private-key $PRIVATE_KEY --gas-limit 10000000

# Step 2 — Deploy proxy
INIT_DATA=$(cast abi-encode "initialize(address)" 0xADMIN_ADDRESS)

forge create @openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy \
  --rpc-url https://rpc.thaifi.com \
  --private-key $PRIVATE_KEY --gas-limit 5000000 \
  --constructor-args 0xIMPLEMENTATION_ADDRESS $INIT_DATA

15. Verify Contracts

Bash
forge verify-contract 0xYOUR_CONTRACT_ADDRESS \
  src/MyContract.sol:MyContract \
  --chain-id 7 \
  --verifier sourcify \
  --verifier-url https://contracts.thaifi.com

16. Tempo Transactions (0x76)

ThaiFi uses Tempo's transaction envelope (type 0x76) which extends EIP-1559 with:

JSON-RPC Methods

Bash
# Fill missing fields (nonce, gas, fee payer)
eth_fillTransaction

# Broadcast and wait for receipt
eth_sendRawTransactionSync

# Sign-only policy
eth_signRawTransaction

17. Decode Data

Decode Function Selector

Bash
cast 4byte 0xa6c07924
# Output: distributeFees(address,address)

Decode Calldata

Bash
cast pretty-calldata 0xa6c079240000000000000000000000005266dfa5ae013674f8fdc832b7c601b838d94ee600000000000000000000000020c0000000000000000000000000000000000000

18. Example Scripts

Check All Tokens

Bash
#!/bin/bash
RPC=https://rpc.thaifi.com
TOKENS=(
  "0x20C0000000000000000000000000000000000000"
)

for TOKEN in "${TOKENS[@]}"; do
  echo "=== Token: $TOKEN ==="
  echo "Name:       $(cast call $TOKEN 'name()(string)' --rpc-url $RPC)"
  echo "Symbol:     $(cast call $TOKEN 'symbol()(string)' --rpc-url $RPC)"
  echo "Currency:   $(cast call $TOKEN 'currency()(string)' --rpc-url $RPC)"
  echo "Decimals:   $(cast call $TOKEN 'decimals()(uint8)' --rpc-url $RPC)"
  echo "Supply:     $(cast call $TOKEN 'totalSupply()(uint256)' --rpc-url $RPC)"
  echo ""
done

Check Validator Status

Bash
#!/bin/bash
RPC=https://rpc.thaifi.com
FEE_MANAGER=0xfeec000000000000000000000000000000000000
pathUSD=0x20C0000000000000000000000000000000000000
VALIDATORS=(
  "0x5266Dfa5ae013674f8FdC832b7c601B838D94eE6"
)

for V in "${VALIDATORS[@]}"; do
  echo "=== Validator: $V ==="
  echo "Fee Token:    $(cast call $FEE_MANAGER 'validatorTokens(address)(address)' $V --rpc-url $RPC)"
  echo "Collected Fees: $(cast call $FEE_MANAGER 'collectedFees(address,address)(uint256)' $V $pathUSD --rpc-url $RPC)"
  echo ""
done

19. Use Case: Issue a Stablecoin

End-to-end: create a TIP-20 token, enable it as a gas fee token, and mint supply — the exact flow used to launch wrapped USDC on ThaiFi. Examples sign with --ledger; replace it with --private-key $PRIVATE_KEYif you don't use a Ledger.

Step 1 — Create the token via the TIP-20 Factory

Bash
cast send 0x20fc000000000000000000000000000000000000 \
  "createToken(string,string,string,address,address,bytes32)" \
  "J Point" "JPOINT" "USD" \
  0x20C0000000000000000000000000000000000000 \
  0xYOUR_WALLET \
  0x0000000000000000000000000000000000000000000000000000000000000002 \
  --rpc-url https://rpc.thaifi.com --ledger

quoteToken must be pathUSD (address(0) reverts). The salt must be unique per wallet — reusing one reverts TokenAlreadyExists.

Step 2 — Get the token address

Open the transaction on https://exp.thaifi.com — the new token address is in the TokenCreated event. Then export it:

Bash
export TOKEN=0x...   # your new token address

Step 3 — Grant the Minter role

The factory does not always auto-assign ISSUER_ROLE. Grant it to your wallet (required before minting):

Bash
cast send $TOKEN \
  "grantRole(bytes32,address)" \
  0x114e74f6ea3bd819998f78687bfcb11b140da08e9b7d222fa9c1f1ba1f2aa122 \
  0xYOUR_WALLET \
  --rpc-url https://rpc.thaifi.com --ledger

Step 4 — Enable the token for gas fees (Fee AMM)

Seed the Fee AMM with pathUSD so fees paid in your token can be converted for validators. First approve pathUSD for the Fee Manager:

Bash
cast send 0x20C0000000000000000000000000000000000000 \
  "approve(address,uint256)" \
  0xfeec000000000000000000000000000000000000 10000000 \
  --rpc-url https://rpc.thaifi.com --ledger

Then allow your token to be swapped into pathUSD for fees by minting Fee AMM liquidity:

Bash
cast send 0xfeec000000000000000000000000000000000000 \
  "mint(address,address,uint256,address)" \
  $TOKEN \
  0x20C0000000000000000000000000000000000000 \
  10000000 \
  0xYOUR_WALLET \
  --rpc-url https://rpc.thaifi.com --ledger

Only pathUSD is taken — your token's side of the pool starts at zero and fills automatically as users pay fees in it. 10 pathUSD covers tens of thousands of transactions.

Step 5 — Mint your token

Bash
# Mint 1,000 tokens (6 decimals → 1000 * 10^6)
cast send $TOKEN "mint(address,uint256)" \
  0xYOUR_WALLET 1000000000 \
  --rpc-url https://rpc.thaifi.com --ledger

Result: any account holding only your token can now transact — fees (~$0.0002/tx) are charged in your token and auto-converted through the Fee AMM. To also make the token tradeable, add orderbook liquidity on the Stablecoin DEX (separate system).

20. Useful Resources

Building with an AI agent?

Download the SKILL.md file and add it to your project. It gives Claude Code, Cursor, and other vibe-coding agents full context about ThaiFi — chain config, gas model, system contracts, and all the commands above.

Download SKILL.md
↑ Back to top