Skip to main content
TIP-20 is Tempo’s enshrined token standard — an ERC-20 superset with built-in features for high-throughput stablecoin payments.
ERC-20 Compatible: TIP-20 tokens are fully compatible with existing ERC-20 infrastructure, tools, and integrations. The extensions are additive.

Why TIP-20?

Traditional ERC-20 tokens lack features critical for institutional payment infrastructure:

No Payment Reconciliation

Standard transfers have no native way to attach invoice numbers, references, or memo fields.

Unpredictable Throughput

Token transfers compete for block space with all other transactions, causing congestion.

Per-Token Compliance

Each token implements its own transfer restrictions, causing inconsistency and integration overhead.

High Gas Costs

Standard ERC-20 transfers cost 65k-100k+ gas due to inefficient storage patterns.
TIP-20 addresses these issues through protocol-level integration.

Core Features

1. Payment Lanes

TIP-20 transfers access dedicated payment lanes with guaranteed capacity:
  • 450M gas/block reserved for payment transactions
  • General transactions capped at 30M gas, ensuring payment throughput
  • Predictable inclusion: Payment lane priority prevents noisy-neighbor problems
At 50,000 gas per TIP-20 transfer and 450M gas payment capacity, Tempo can process ~9,000 transfers per block or ~18,000 TPS at 500ms block times.

2. On-Transfer Memos

Attach 32-byte memo fields directly to transfers for reconciliation:
import { ITIP20 } from '@tempo/contracts';

const receipt = await token.transferWithMemo(
  recipient,
  parseUnits('1000', 6), // 1000 tokens
  ethers.encodeBytes32String('INV-2024-001') // Invoice reference
);

// Memo is indexed and retrievable from logs
Event Emitted:
event TransferWithMemo(
    address indexed from,
    address indexed to,
    uint256 amount,
    bytes32 indexed memo
);

3. Commitment Patterns

For large data or PII, use hash commitments to keep sensitive data off-chain:
Store a hash of off-chain data on-chain for verification:
const offChainData = JSON.stringify({
  invoice_number: 'INV-2024-001',
  description: 'Monthly subscription',
  customer_details: { /* PII */ },
});

const hash = keccak256(toUtf8Bytes(offChainData));
await token.transferWithMemo(recipient, amount, hash);

// Store offChainData in your database, indexed by hash
Verification: Recipients can verify received data matches the hash commitment.
Store a reference to external data (URL, database key, etc.):
const locator = ethers.encodeBytes32String('https://api.example.com/invoice/12345');
await token.transferWithMemo(recipient, amount, locator);
Use case: Large documents, multi-page invoices, detailed transaction metadata.
Privacy Consideration: Memos and hashes are public on-chain. Never put raw PII in the memo field — always use hash commitments.

4. TIP-403 Policy Registry

Shared compliance policies across multiple tokens:
// Create a policy once
ITIP403Registry registry = ITIP403Registry(POLICY_REGISTRY_ADDRESS);
uint256 policyId = registry.createPolicy(transferHooksAddress);

// Apply to multiple tokens
token1.setPolicyId(policyId);
token2.setPolicyId(policyId);
token3.setPolicyId(policyId);

// Update policy once, enforced everywhere
registry.updatePolicy(policyId, newTransferHooksAddress);
Benefits:
  • Single update propagates: Change compliance rules for all tokens at once
  • Consistent enforcement: Same rules across token portfolio
  • Reduced integration overhead: Deploy hooks contract once, apply to many tokens

TIP-403 Specification

Complete documentation of the Policy Registry system

Token Lifecycle

Deployment via TIP-20 Factory

TIP-20 tokens are deployed through the TIP-20 Factory precompile for gas efficiency:
import { ITIP20Factory } from '@tempo/contracts';

const factory = ITIP20Factory.connect(TIP20_FACTORY_ADDRESS, signer);

const tx = await factory.createToken(
  'AlphaUSD',           // name
  'AUSD',               // symbol
  6,                    // decimals
  ownerAddress,         // owner
  parseUnits('1000000', 6), // initial supply
  0,                    // policy ID (0 = no policy)
  ethers.ZeroAddress    // quote token (for DEX)
);

const receipt = await tx.wait();
const tokenAddress = receipt.logs[0].address; // TIP-20 address
Token Address Format: 0x20c0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • All TIP-20 tokens share the 0x20c0 prefix
  • Remaining 18 bytes uniquely identify the token
  • Enables efficient precompile routing

Token Roles

TIP-20 implements OpenZeppelin-style role-based access control:

Owner

Full control over token configuration, role assignments, and critical operations.

Minter

Can mint new tokens to any address (if not immutably capped).

Burner

Can burn tokens from any address (for redemptions, deflationary mechanics).

Pauser

Can pause/unpause transfers (emergency stop mechanism).
// Grant roles
token.grantRole(MINTER_ROLE, minterAddress);
token.grantRole(BURNER_ROLE, burnerAddress);

// Revoke roles
token.revokeRole(MINTER_ROLE, minterAddress);

Gas Costs

TIP-20 is optimized for low-cost transfers:
OperationGas CostUSD @ 0.1¢/50k gas
Transfer to existing address~50,000$0.001 (0.1¢)
Transfer to new address~300,000$0.006 (0.6¢)
Transfer with memo~52,000$0.001 (0.1¢)
Approve~45,000$0.0009 (0.09¢)
Mint~55,000$0.0011 (0.11¢)
Burn~55,000$0.0011 (0.11¢)
New address cost: First-time transfers to an address cost ~250k gas more due to TIP-1000 state creation pricing (anti-spam measure).

Comparison with ERC-20

Why TIP-20 is cheaper:
  • Enshrined precompile (no contract call overhead)
  • Optimized storage layout
  • Efficient balance tracking
  • Payment lane reduces contention

Advanced Features

Permit (EIP-2612)

Gasless approvals via off-chain signatures:
import { signTypedData } from 'viem';

const domain = {
  name: await token.name(),
  version: '1',
  chainId: TEMPO_CHAIN_ID,
  verifyingContract: tokenAddress,
};

const types = {
  Permit: [
    { name: 'owner', type: 'address' },
    { name: 'spender', type: 'address' },
    { name: 'value', type: 'uint256' },
    { name: 'nonce', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
  ],
};

const value = {
  owner: ownerAddress,
  spender: spenderAddress,
  value: parseUnits('1000', 6),
  nonce: await token.nonces(ownerAddress),
  deadline: Math.floor(Date.now() / 1000) + 3600, // 1 hour
};

const signature = await signTypedData({ domain, types, value });
const { v, r, s } = signature;

// Spender can now execute permit + transfer atomically
await token.permit(owner, spender, value.value, value.deadline, v, r, s);
await token.transferFrom(owner, recipient, value.value);

Rewards Distribution

Protocol-level reward accrual for validators:
// Validators earn rewards from TIP-20 activity
function setRewardRecipient(address recipient) external {
    // Direct rewards to another address (e.g., staking pool)
}

function claimRewards() external {
    // Claim accumulated rewards from TIP-20 transfers
}
Rewards are distributed to validators based on their participation in consensus and block production. Token holders do not need to do anything.

Quote Token (DEX Integration)

Tokens can specify a quote token for automated DEX pairing:
// Set quote token to create DEX pair
await token.setQuoteToken(usdcAddress);

// Initiates quote token update (48-hour delay)
await token.setNextQuoteToken(usdtAddress);

// Complete update after delay
await token.completeQuoteTokenUpdate();
Use case: Automatic liquidity routing through the Stablecoin DEX precompile.

Compliance & Transfer Policies

Transfer Hooks (TIP-403)

Transfer policies are enforced via hooks contracts registered in TIP-403:
interface ITransferPolicy {
    function beforeTransfer(
        address token,
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
    
    function afterTransfer(
        address token,
        address from,
        address to,
        uint256 amount
    ) external;
}
Example Policies:
  • KYC/AML: Verify sender/recipient are on whitelist
  • Transfer limits: Enforce daily/monthly caps
  • Jurisdiction restrictions: Block transfers to sanctioned addresses
  • Business hours: Only allow transfers during specific times

Pause Mechanism

Emergency transfer halt:
// Pause all transfers
await token.pause();

// Approvals still work (non-value-moving)
await token.approve(spender, amount); // ✅ Allowed

// Transfers revert
await token.transfer(recipient, amount); // ❌ Reverts

// Resume transfers
await token.unpause();
Pause privileges: Only addresses with the PAUSER role can pause/unpause. Use multi-sig or governance for production.

Integration Guide

Querying Token Metadata

import { ITIP20 } from '@tempo/contracts';

const token = ITIP20.connect(tokenAddress, provider);

const name = await token.name();
const symbol = await token.symbol();
const decimals = await token.decimals();
const totalSupply = await token.totalSupply();
const balance = await token.balanceOf(userAddress);

Watching Transfer Events

// Standard ERC-20 Transfer event
token.on('Transfer', (from, to, amount, event) => {
  console.log(`${formatUnits(amount, 6)} transferred from ${from} to ${to}`);
});

// TIP-20 TransferWithMemo event
token.on('TransferWithMemo', (from, to, amount, memo, event) => {
  const memoString = ethers.toUtf8String(memo).replace(/\0/g, '');
  console.log(`Transfer memo: ${memoString}`);
});

Allowance Pattern

// Standard ERC-20 approve/transferFrom flow
await token.connect(owner).approve(spender, parseUnits('1000', 6));

// Spender executes transfer
await token.connect(spender).transferFrom(
  owner,
  recipient,
  parseUnits('500', 6)
);

// Check remaining allowance
const remaining = await token.allowance(owner, spender);

Compatibility Matrix

ERC-20 FeatureTIP-20 SupportNotes
transfer✅ FullStandard transfer
transferFrom✅ FullAllowance-based transfer
approve✅ FullSet spending allowance
balanceOf✅ FullQuery balance
totalSupply✅ FullQuery total supply
decimals✅ FullToken decimals
name✅ FullToken name
symbol✅ FullToken symbol
permit (EIP-2612)✅ FullGasless approvals
Additional TIP-20 Features:
  • transferWithMemo - Transfer with 32-byte memo
  • setPolicyId - Apply TIP-403 policy
  • setQuoteToken - Configure DEX pairing
  • Role-based minting/burning/pausing

Best Practices

Attach invoice numbers, order IDs, or reference codes to enable automatic reconciliation. Use hash commitments for sensitive data.
Use the TIP-20 Factory precompile for gas-efficient deployment and guaranteed address format.
Define your compliance requirements before mainnet. TIP-403 makes updates easy, but design thoughtfully.
OWNER, MINTER, and PAUSER roles should be controlled by multi-sig or governance contracts in production.
TIP-403 policies affect all tokens using that policy. Test updates thoroughly on testnet before applying to mainnet.

SDK Examples

TypeScript SDK

Complete TIP-20 integration examples with memos, policies, and advanced features.

Rust SDK

Type-safe TIP-20 contract bindings for Rust applications.

Further Reading

TIP-20 Specification

Complete technical specification of the TIP-20 standard

TIP-403 Policy Registry

Shared compliance policies across multiple tokens

Stablecoin DEX

On-chain order book for stablecoin swaps

Fee AMM

Multi-currency fee payment mechanism