Tenzro Testnet is live. Get testnet TNZO

Tempo Network Integration

Tempo is a decentralized network for stablecoin payments and machine-to-machine transactions. Co-designed with Stripe as part of the Machine Payments Protocol (MPP) ecosystem, Tempo provides a settlement layer for cross-border stablecoin transfers with fast finality and low fees. Tenzro Network integrates with Tempo to enable direct participation in the Tempo network, allowing AI agents and model providers to settle payments in stablecoins (USDC, USDT) while maintaining TNZO as the native gas token.

Why Tempo Integration?

Tempo integration provides several key benefits for Tenzro Network participants:

  • Stablecoin Settlement: Users and agents can pay for AI inference in USDC/USDT instead of volatile TNZO, reducing currency risk for model providers.
  • Cross-Network Transfers: Bridge assets between Tenzro and other Tempo-connected networks (Ethereum, Solana, Polygon, etc.) without custodial exchanges.
  • Fast Finality: Tempo provides sub-second transaction finality compared to Ethereum's 12-15 minutes, improving payment UX for streaming inference.
  • Low Fees: Tempo optimizes for micropayments with fractional-cent fees, making per-token AI billing economically viable.
  • Compliance: Tempo supports regulated stablecoin issuers (Circle USDC, Tether USDT) with built-in AML/KYC hooks.

Architecture Overview

Tenzro's Tempo integration consists of three main components:

┌─────────────────────────────────────────────────────┐ │ Tenzro Network │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ TempoBridgeAdapter │ │ │ │ - Token transfers to/from Tempo │ │ │ │ - Finality verification │ │ │ │ - Event monitoring │ │ │ └──────────────┬───────────────────────────────┘ │ │ │ │ │ ┌──────────────▼───────────────────────────────┐ │ │ │ TempoParticipant │ │ │ │ - Network registration │ │ │ │ - Identity management │ │ │ │ - TIP-20 token catalog │ │ │ └──────────────┬───────────────────────────────┘ │ │ │ │ │ ┌──────────────▼───────────────────────────────┐ │ │ │ Tip20Token / Tip20Balance │ │ │ │ - Token metadata (USDC, USDT, etc.) │ │ │ │ - Balance queries │ │ │ │ - Transfer operations │ │ │ └──────────────────────────────────────────────┘ │ │ │ └──────────────────┬──────────────────────────────────┘ │ │ HTTP/WebSocket │ ┌─────────▼─────────────────┐ │ Tempo Network │ │ - Stablecoin settlement │ │ - TIP-20 token registry │ │ - Cross-chain bridges │ └────────────────────────────┘

TIP-20 Token Standard

TIP-20 (Tempo Improvement Proposal 20) is the token standard used by the Tempo network. It defines metadata, transfer semantics, and on-chain representation for fungible tokens like stablecoins.

Tip20Token

The Tip20Token struct represents a TIP-20 token on Tempo:

pub struct Tip20Token { pub token_id: String, // Unique token identifier pub name: String, // Human-readable name ("USD Coin") pub symbol: String, // Ticker symbol ("USDC") pub decimals: u8, // Decimal places (6 for USDC, 18 for TNZO) pub issuer: String, // Issuer address (Circle for USDC) pub total_supply: u64, // Total circulating supply pub network: String, // Origin network ("ethereum", "solana", "tenzro") pub contract_address: Option<String>, // Contract address on origin network } // Common TIP-20 tokens on Tempo let usdc = Tip20Token { token_id: "tip20:usdc".into(), name: "USD Coin".into(), symbol: "USDC".into(), decimals: 6, issuer: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".into(), // Circle total_supply: 25_000_000_000_000_000, // 25 billion USDC network: "ethereum".into(), contract_address: Some("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".into()), }; let usdt = Tip20Token { token_id: "tip20:usdt".into(), name: "Tether USD".into(), symbol: "USDT".into(), decimals: 6, issuer: "0xdac17f958d2ee523a2206206994597c13d831ec7".into(), // Tether total_supply: 95_000_000_000_000_000, // 95 billion USDT network: "ethereum".into(), contract_address: Some("0xdac17f958d2ee523a2206206994597c13d831ec7".into()), };

Tip20Balance

The Tip20Balance struct represents a user's balance for a specific TIP-20 token:

pub struct Tip20Balance { pub token_id: String, // References Tip20Token pub address: String, // Owner address pub balance: u64, // Balance in smallest denomination pub locked: u64, // Locked balance (escrow, pending transfers) pub available: u64, // Available balance (balance - locked) } // Query balance let balance = tempo_participant .get_balance("tip20:usdc", &user_address) .await?; println!("USDC Balance: {} (available: {})", balance.balance as f64 / 1e6, balance.available as f64 / 1e6 );

TempoParticipant

The TempoParticipant struct manages Tenzro's registration with the Tempo network. Each Tenzro node can register as a Tempo participant to send/receive TIP-20 tokens:

use tenzro_payments::tempo::*; // Initialize Tempo participant let tempo_config = TempoConfig { endpoint: "https://api.tempo.network".into(), participant_id: Some("tenzro-node-1".into()), api_key: Some(std::env::var("TEMPO_API_KEY")?), network: "mainnet".into(), }; let participant = TempoParticipant::new(tempo_config).await?; // Register with Tempo network participant.register( "Tenzro Node 1".into(), node_wallet_address.clone(), vec!["tip20:usdc".into(), "tip20:usdt".into()], // Supported tokens ).await?; println!("Registered with Tempo network: {}", participant.participant_id); // Query supported tokens let tokens = participant.list_supported_tokens().await?; for token in tokens { println!("Token: {} ({}) - {} decimals", token.name, token.symbol, token.decimals); } // Query balance let usdc_balance = participant.get_balance("tip20:usdc", &node_wallet_address).await?; println!("USDC balance: {}", usdc_balance.balance as f64 / 1e6);

TempoBridgeAdapter

The TempoBridgeAdapter implements the BridgeAdapter trait for cross-network token transfers. It bridges TIP-20 tokens between Tenzro and other networks connected to Tempo:

Sending Tokens from Tenzro to Tempo

use tenzro_bridge::{BridgeAdapter, TenzroMessage}; use tenzro_payments::tempo::TempoBridgeAdapter; let tempo_bridge = TempoBridgeAdapter::new(tempo_participant.clone()); // Bridge 100 USDC from Tenzro to Ethereum via Tempo let message = TenzroMessage { id: Uuid::new_v4().to_string(), source_chain: "tenzro-mainnet".into(), dest_chain: "ethereum".into(), sender: tenzro_sender_address.clone(), recipient: ethereum_recipient_address.clone(), asset: "tip20:usdc".into(), amount: 100_000_000, // 100 USDC (6 decimals) data: vec![], timestamp: chrono::Utc::now().timestamp() as u64, nonce: 1, signature: None, signer_pubkey: None, }; // Send via Tempo bridge let tx_hash = tempo_bridge.send_message(&message).await?; println!("Bridge transfer initiated: {}", tx_hash); // Monitor transfer status loop { let status = tempo_bridge.verify_message(&message.id).await?; match status.as_str() { "pending" => { println!("Transfer pending..."); tokio::time::sleep(Duration::from_secs(5)).await; } "confirmed" => { println!("Transfer confirmed on source chain"); } "delivered" => { println!("Transfer delivered to destination chain"); break; } "failed" => { println!("Transfer failed: {}", status); break; } _ => {} } } // Verify finality let finality = tempo_bridge.check_finality(&tx_hash).await?; println!("Finality: {:?}", finality);

Receiving Tokens from Tempo to Tenzro

// Listen for incoming transfers from Tempo let mut event_stream = tempo_bridge.subscribe_events().await?; while let Some(event) = event_stream.next().await { match event { TempoEvent::IncomingTransfer { transfer_id, from, to, token, amount } => { println!("Incoming transfer: {} {} from {} to {}", amount as f64 / 1e6, token, from, to); // Verify transfer on Tempo network let verified = tempo_participant.verify_transfer(&transfer_id).await?; if verified { // Credit recipient account on Tenzro account_store.credit( &to, amount, token.parse()?, // Convert "tip20:usdc" to Asset enum ).await?; println!("Transfer credited to {}", to); } } TempoEvent::FinalityReached { transfer_id } => { println!("Transfer {} reached finality", transfer_id); } _ => {} } }

Using Tempo with MPP Payments

Tempo integration enables MPP payments to be settled in stablecoins instead of TNZO. This is particularly useful for AI inference payments where providers prefer predictable fiat-equivalent revenue:

use tenzro_payments::mpp::*; use tenzro_payments::tempo::*; // Model provider creates MPP challenge requesting USDC payment let challenge = MppChallenge { challenge_id: Uuid::new_v4().to_string(), resource_url: "https://api.provider.com/inference".into(), amount: 500_000, // 0.5 USDC (6 decimals) currency: "tip20:usdc".into(), // Request payment in Tempo USDC expires_at: chrono::Utc::now() + chrono::Duration::minutes(5), recipient: provider_tempo_address.clone(), metadata: Some(HashMap::from([ ("model_id".into(), "gpt-4".into()), ("settlement_network".into(), "tempo".into()), ])), }; // Client creates credential with Tempo settlement let credential = MppCredential { credential_id: Uuid::new_v4().to_string(), challenge_id: challenge.challenge_id.clone(), payer: client_tempo_address.clone(), recipient: challenge.recipient.clone(), amount: challenge.amount, currency: challenge.currency.clone(), signature: vec![], timestamp: chrono::Utc::now(), }; // Sign with wallet let payload = credential.signing_payload(); let signature = wallet.sign(&payload).await?; credential.signature = signature; // Server verifies and settles via Tempo let mpp = MppProtocol::new(challenge_store.clone(), settlement_engine.clone()); let verification = mpp.verify_credential(&credential).await?; if verification.verified { // Execute Tempo transfer let transfer = tempo_participant.transfer( &credential.payer, &credential.recipient, credential.amount, "tip20:usdc", ).await?; // Create receipt with Tempo transaction hash let receipt = MppReceipt { receipt_id: Uuid::new_v4().to_string(), credential_id: credential.credential_id.clone(), settlement_tx: Some(transfer.tx_hash.clone()), amount: credential.amount, currency: credential.currency.clone(), timestamp: chrono::Utc::now(), server_signature: vec![], }; // Return receipt HttpResponse::Ok() .header("X-Payment-Receipt", base64::encode(serde_json::to_vec(&receipt)?)) .json(&inference_result) }

Cross-Chain Settlement Flow

Here's a complete example of an AI inference payment where the user pays from Ethereum USDC and the provider receives on Tenzro:

// 1. USER (Ethereum): Initiate inference request // User has USDC on Ethereum mainnet, wants to use Tenzro AI model // 2. USER → TEMPO: Bridge USDC to Tempo network let bridge_tx = ethereum_usdc_contract.approve(tempo_bridge_address, 10_000_000); // 10 USDC let tempo_deposit = tempo_ethereum_bridge.deposit(10_000_000, "usdc", user_tempo_address); // 3. TEMPO: Confirm deposit, credit user's Tempo account // User now has 10 USDC on Tempo network // 4. USER → TENZRO MODEL PROVIDER: Request inference with MPP challenge let challenge = MppChallenge { amount: 500_000, // 0.5 USDC currency: "tip20:usdc".into(), recipient: provider_tempo_address.clone(), // ... }; // 5. USER → TEMPO: Transfer USDC to provider let tempo_transfer = tempo_participant.transfer( &user_tempo_address, &provider_tempo_address, 500_000, "tip20:usdc", ).await?; // 6. USER → TENZRO: Submit credential with Tempo transfer proof let credential = MppCredential { amount: 500_000, currency: "tip20:usdc".into(), // metadata includes tempo_transfer.tx_hash // ... }; // 7. TENZRO MODEL PROVIDER: Verify credential and Tempo transfer let tempo_tx = tempo_participant.get_transaction(&tempo_transfer.tx_hash).await?; assert!(tempo_tx.to == provider_tempo_address); assert!(tempo_tx.amount >= 500_000); // 8. TENZRO MODEL PROVIDER: Execute inference, return result let inference_result = model.infer(user_request).await?; // 9. PROVIDER → TEMPO → TENZRO: Bridge USDC earnings back to Tenzro (optional) let bridge_back = tempo_bridge.send_message(&TenzroMessage { source_chain: "tempo".into(), dest_chain: "tenzro-mainnet".into(), sender: provider_tempo_address.clone(), recipient: provider_tenzro_address.clone(), asset: "tip20:usdc".into(), amount: 500_000, // ... }).await?; // Provider now has 0.5 USDC on Tenzro, can swap to TNZO or hold

TempoConfig

The TempoConfig struct configures the Tempo network connection:

pub struct TempoConfig { pub endpoint: String, // Tempo API endpoint pub participant_id: Option<String>, // Participant identifier pub api_key: Option<String>, // API key for authenticated access pub network: String, // "mainnet", "testnet", "devnet" } impl Default for TempoConfig { fn default() -> Self { Self { endpoint: "https://api.tempo.network".into(), participant_id: None, api_key: None, network: "mainnet".into(), } } } // Load config from environment let config = TempoConfig { endpoint: std::env::var("TEMPO_ENDPOINT") .unwrap_or_else(|_| "https://api.tempo.network".into()), participant_id: std::env::var("TEMPO_PARTICIPANT_ID").ok(), api_key: std::env::var("TEMPO_API_KEY").ok(), network: std::env::var("TEMPO_NETWORK") .unwrap_or_else(|_| "mainnet".into()), };

Feature Flag

Tempo integration is gated behind the tempo-bridge feature flag in tenzro-payments. This allows nodes to optionally include Tempo support:

# Cargo.toml [dependencies] tenzro-payments = { version = "0.1.0", features = ["tempo-bridge"] } # Without Tempo support (smaller binary, no stablecoin integration) tenzro-payments = { version = "0.1.0", default-features = false, features = ["mpp", "x402"] }

Deployment Considerations

Network Participation: To use Tempo, Tenzro nodes must register as Tempo participants with a valid API key. Contact Tempo Labs for participant registration.

Token Whitelisting: Only tokens explicitly supported by both Tempo and Tenzro can be bridged. The initial whitelist includes USDC and USDT; additional tokens require governance approval.

Bridge Security: The Tempo bridge uses multi-signature validation and time-locks for large transfers. All bridge transactions are auditable on both networks.

Gas Costs: Bridge transfers incur gas costs on both source and destination chains. Tenzro nodes should maintain TNZO balances for gas, even when settling in stablecoins.

Finality: Tempo provides fast finality (sub-second), but cross-chain bridges may introduce latency based on source chain finality. Ethereum transfers require ~15 minutes for finality.

Current Implementation Status

As documented in CLAUDE.md, the Tempo integration is currently a stub implementation:

Status: Architectural prototype - API contracts defined but not connected to live Tempo network.

Implemented: Data structures (TempoConfig, TempoBridgeAdapter, Tip20Token, Tip20Balance, TempoParticipant), trait implementations for BridgeAdapter, type-safe API.

Not Implemented: Actual HTTP/WebSocket connection to Tempo network, real balance queries (currently return 0), real transfers (currently return fake tx hashes), finality verification (currently always returns Finalized).

Phase 4 development priorities include connecting the Tempo adapter to the live Tempo network. See the Development Priorities section in the Architecture documentation for the full roadmap.

Next Steps