Settle Payments on Tempo
Tempo is a stablecoin-native settlement chain co-designed by Stripe. Tenzro's tempo-bridge feature lets nodes participate directly — signing EIP-155 Secp256k1 transactions via k256, submitting eth_sendRawTransactioncalls, and querying balances — to settle MPP/x402 payments on Tempo rather than (or in addition to) the Tenzro Ledger.
What You'll Build
- A
TempoConfigandTempoParticipantbound to your DID - Direct TIP-20 stablecoin transfers with real EIP-155 signing
- MPP-over-Tempo settlement in an Axum/Actix service
- Tempo ↔ Tenzro bridging via
TempoBridgeAdapter
Flow Diagram
Tempo settlement flow (server-side, HTTP 402)
client resource server Tempo chain
------ --------------- -----------
│ │ │
│ GET /inference (no auth) │ │
├──────────────────────────────────►│ │
│ │ │
│ 402 Payment Required │ │
│◄──────────────────────────────────┤ │
│ challenge: { rail: "tempo", │ │
│ amount: "0.01", │ │
│ token: "USDC", │ │
│ payee: "0x..." } │ │
│ │ │
│ sign + submit tempo tx │ │
├────────────────────────────────────────────────────────────────────►
│ │ │
│ │ confirmed (1 block) │
│ │◄───────────────────────────────┤
│ │ │
│ retry + X-PAYMENT-TX header │ │
├──────────────────────────────────►│ │
│ │ │
│ │ verify inclusion via RPC │
│ ├────────────────────────────────►
│ │ proof │
│ │◄───────────────────────────────┤
│ 200 OK + X-PAYMENT-RECEIPT │ │
│◄──────────────────────────────────┤ │Step 1: Configure a Participant
// tempo.toml — or inline TempoConfig
[tempo]
rpc_url = "https://rpc.tempo.example"
chain_id = 7338
participant_id = "did:tenzro:machine:c3d4..."
default_stablecoin = "USDC"
signing_key = "secp256k1:..." // or provision via MPC walletuse tenzro_payments::tempo::{TempoConfig, TempoParticipant};
let cfg = TempoConfig::from_toml("tempo.toml")?;
let participant = TempoParticipant::new(cfg).await?;
// Query balance on Tempo
let bal = participant.balance_of("USDC", "0xWalletOnTempo...").await?;
println!("{} USDC", bal);Step 2: Direct TIP-20 Transfer
TempoParticipant::transfer implements the full EIP-155 signing pipeline:
- Build EIP-1559 transaction (
max_fee_per_gas,max_priority_fee_per_gas, gas limit, nonce) - RLP-encode the unsigned transaction
- Take
keccak256digest - Sign with the participant's secp256k1 key via
k256 - Serialize with
v = recId + 35 + 2 * chainId - Submit via
eth_sendRawTransactionand poll for inclusion
// Sign and submit a TIP-20 transfer — full EIP-155 pipeline under the hood:
// * Construct EIP-1559 tx
// * RLP encode
// * Keccak-256 digest
// * Secp256k1 sign via k256
// * Serialize with v = recId + 35 + (2 * chainId)
// * eth_sendRawTransaction to the Tempo RPC
let receipt = participant.transfer(
"USDC", // TIP-20 token symbol
"0xRecipientOnTempo...",
"10.50", // decimal string
).await?;
println!("tx: {}", receipt.tx_hash);
println!("block: {}", receipt.block_number);
println!("status: {}", receipt.status); // Success | RevertedStep 3: Settle MPP over Tempo
This is the core production use case — the same MPP credential that your HTTP middleware already verifies can be settled on Tempo instead of the Tenzro Ledger. The MPP receipt simply references the Tempo tx hash:
// MPP credential settled through Tempo
use tenzro_payments::{MppPaymentServer, PaymentProtocol};
let mpp = MppPaymentServer::new(/* ... */);
let tempo = TempoParticipant::new(cfg).await?;
// 1. Client presents MPP credential
let credential = request.headers()
.get("X-PAYMENT-MPP")
.ok_or("missing credential")?;
// 2. Verify signature + session state
let verified = mpp.verify_credential(credential).await?;
// 3. Settle on Tempo in the background
let tempo_settlement = tempo.transfer(
&verified.stablecoin,
&verified.payee_wallet,
&verified.amount,
).await?;
// 4. Return MPP receipt referencing the Tempo tx hash
let receipt = mpp.issue_receipt(&verified, tempo_settlement.tx_hash)?;Step 4: Tempo ↔ Tenzro Bridging
// Cross-chain Tempo ↔ Tenzro settlement via TempoBridgeAdapter
use tenzro_payments::tempo::TempoBridgeAdapter;
let bridge = TempoBridgeAdapter::new(tempo_cfg, tenzro_rpc).await?;
// Deposit: move USDC from Tenzro to Tempo
let deposit_tx = bridge.deposit_to_tempo(
"USDC",
"100.0",
"did:tenzro:machine:c3d4...",
).await?;
// Withdraw: pull USDC settled on Tempo back to Tenzro
let withdraw_tx = bridge.withdraw_to_tenzro(
"USDC",
"50.0",
).await?;Step 5: CLI
# Register as a Tempo participant (provisions MPC wallet for Tempo chain)
tenzro payment tempo register \
--stablecoin USDC \
--rpc-url https://rpc.tempo.example
# Check a Tempo balance
tenzro payment tempo balance --token USDC --address 0xWalletOnTempo...
# Direct transfer
tenzro payment tempo transfer \
--token USDC \
--to 0xRecipientOnTempo... \
--amount 10.50
# Settle an outstanding MPP session through Tempo
tenzro payment settle \
--session-id mpp-sess-01HR... \
--rail tempoWhen to use Tempo vs the Tenzro Ledger. The Tenzro Ledger is purpose-built for verifiable AI workloads (TEE + ZK + identity). Tempo is optimized for high-throughput stablecoin flow with tight Stripe-pipeline integration. A common pattern: bill AI usage in TNZO on the Tenzro Ledger for the crypto-native path, and settle stablecoin flows (USDC payroll, merchant payouts) on Tempo. The TempoBridgeAdapter moves balances between the two.
What You Learned
- EIP-155 pipeline — RLP + keccak + secp256k1 +
v = recId + 35 + 2 * chainId - TempoParticipant — balance queries, direct transfers, receipt polling
- MPP → Tempo — settle HTTP 402 credentials on the Tempo chain
- Bridge adapter — move stablecoin balances between Tenzro and Tempo
Next Steps
- See the MPP tutorial for the session-based challenge/credential flow
- See the x402 tutorial for stateless one-shot payments
- Read the Payments reference docs