Tenzro Testnet is live. Get testnet TNZO

Escrow

Tenzro Network's escrow system enables trustless conditional payments with cryptographic proof-based release mechanisms. Escrow settlements ensure that funds are held securely until predetermined conditions are met, verified through ZK proofs, TEE attestations, or multi-party signatures.

Overview

The escrow-based settlement engine provides three primary settlement modes:

  • Immediate settlements — Direct transfer without escrow
  • Escrow-based settlements — Funds locked until proof of service delivery
  • Micropayment channels — Off-chain per-token billing for AI inference

Escrow settlements are particularly useful for AI inference payments, where the payer wants assurance that the model provider delivered valid results before releasing payment. The provider submits a cryptographic proof (ZK proof, TEE attestation, or signature) which is verified before funds are released.

Key Features:

  • Cryptographic proof-based release conditions
  • Support for ZK proofs, TEE attestations, and multi-party signatures
  • Automatic timeout and refund mechanisms
  • Network fee collection (0.5% default)
  • Integration with TDIP identities and delegation scopes

Escrow Creation

Creating an escrow involves locking funds from the payer's account into the settlement engine. The escrow is identified by a unique settlement ID and includes metadata about the service being purchased (e.g., inference request ID, model name, expected proof type).

use tenzro_settlement::{SettlementEngine, SettlementRequest, ServiceProof};
use tenzro_types::{Address, Hash};

// Initialize settlement engine
let engine = SettlementEngine::new(
    account_store.clone(),
    block_store.clone(),
);

// Create escrow settlement request
let settlement_id = Hash::from_hex("0x1234...")?;
let request = SettlementRequest {
    settlement_id: settlement_id.clone(),
    from: Address::from_hex("0xpayer...")?,
    to: Address::from_hex("0xprovider...")?,
    amount: 1_000_000_000_000_000_000, // 1 TNZO
    asset: "TNZO".to_string(),
    proof: None, // Escrow mode - proof submitted later
    metadata: serde_json::json!({
        "type": "ai_inference",
        "model": "gpt-4",
        "inference_id": "inf_abc123",
        "expected_proof": "tee_attestation"
    }),
};

// Create escrow (locks funds)
engine.settle(&request).await?;

When the escrow is created, the settlement engine:

  1. Verifies the payer has sufficient balance
  2. Locks the specified amount in escrow state
  3. Records the escrow with status Pending
  4. Stores metadata for later proof verification

Proof-Based Release

Once the service provider (e.g., AI model inference provider) completes the service, they generate a cryptographic proof and submit it to release the escrowed funds. Tenzro supports multiple proof types:

ZK Proof Release

Zero-knowledge proofs allow providers to prove they executed the inference correctly without revealing the model weights or intermediate computation. Tenzro uses Groth16 SNARKs on BN254 for ~128-bit security.

use tenzro_zk::{ZkProofSystem, InferenceVerificationCircuit};
use tenzro_settlement::ServiceProof;

// Provider generates ZK proof of inference execution
let circuit = InferenceVerificationCircuit {
    model_hash: Hash::from_hex("0xmodel...")?,
    input_hash: Hash::from_hex("0xinput...")?,
    output_hash: Hash::from_hex("0xoutput...")?,
    execution_trace: vec![/* ... */],
};

let zk_system = ZkProofSystem::new();
let (proving_key, _) = zk_system.setup(&circuit)?;
let proof = zk_system.prove(&proving_key, &circuit)?;

// Submit proof to release escrow
let release_request = SettlementRequest {
    settlement_id: settlement_id.clone(),
    from: Address::from_hex("0xpayer...")?,
    to: Address::from_hex("0xprovider...")?,
    amount: 1_000_000_000_000_000_000,
    asset: "TNZO".to_string(),
    proof: Some(ServiceProof::ZeroKnowledge {
        proof_data: proof.to_bytes(),
        public_inputs: vec![
            model_hash.as_bytes().to_vec(),
            input_hash.as_bytes().to_vec(),
            output_hash.as_bytes().to_vec(),
        ],
    }),
    metadata: serde_json::json!({}),
};

engine.settle(&release_request).await?;

TEE Attestation Release

Trusted Execution Environment attestations prove that the inference was executed inside a hardware-protected enclave (Intel TDX, AMD SEV-SNP, AWS Nitro, or NVIDIA GPU TEE). The attestation includes the enclave measurement, runtime data hash, and platform certificate chain.

use tenzro_tee::{TeeProvider, AttestationReport};
use tenzro_settlement::ServiceProof;

// Provider generates TEE attestation
let tee = TeeProvider::detect_tee()?;
let report = tee.generate_attestation(&runtime_data)?;

// Submit attestation to release escrow
let release_request = SettlementRequest {
    settlement_id: settlement_id.clone(),
    from: Address::from_hex("0xpayer...")?,
    to: Address::from_hex("0xprovider...")?,
    amount: 1_000_000_000_000_000_000,
    asset: "TNZO".to_string(),
    proof: Some(ServiceProof::TeeAttestation {
        attestation_data: report.attestation,
        measurement: report.measurement,
        enclave_id: report.enclave_id.unwrap_or_default(),
    }),
    metadata: serde_json::json!({}),
};

engine.settle(&release_request).await?;

Multi-Party Signature Release

For escrows requiring consensus from multiple parties (e.g., marketplace escrow with buyer, seller, and arbiter), multi-party signatures can be used. This leverages Tenzro's MPC wallet system for threshold signatures.

use tenzro_crypto::mpc::{KeyShare, PartialSignature, combine_signatures};
use tenzro_settlement::ServiceProof;

// Each party signs the release message
let message = settlement_id.as_bytes();
let share1 = KeyShare::generate();
let share2 = KeyShare::generate();
let share3 = KeyShare::generate();

let sig1 = share1.sign(message)?;
let sig2 = share2.sign(message)?;

// Combine signatures (2-of-3 threshold)
let combined = combine_signatures(&[sig1, sig2])?;

// Submit multi-party proof
let release_request = SettlementRequest {
    settlement_id: settlement_id.clone(),
    from: Address::from_hex("0xpayer...")?,
    to: Address::from_hex("0xprovider...")?,
    amount: 1_000_000_000_000_000_000,
    asset: "TNZO".to_string(),
    proof: Some(ServiceProof::MultiParty {
        signers: vec![
            Address::from_hex("0xparty1...")?,
            Address::from_hex("0xparty2...")?,
        ],
        signatures: vec![
            sig1.to_bytes(),
            sig2.to_bytes(),
        ],
        threshold: 2,
    }),
    metadata: serde_json::json!({}),
};

engine.settle(&release_request).await?;

Condition Verification

When a proof is submitted to release escrowed funds, the settlement engine performs rigorous verification:

  1. Settlement ID lookup — Verify the escrow exists and is in Pending state
  2. Amount matching — Ensure release amount matches escrowed amount
  3. Proof type validation — Verify proof type matches expected type from metadata
  4. Cryptographic verification — Verify the proof itself:
    • ZK proofs: Verify using Groth16 verifier with public inputs
    • TEE attestations: Verify enclave measurement and certificate chain
    • Multi-party: Verify threshold signatures meet quorum
  5. Public input validation — For ZK proofs, verify public inputs (model hash, input hash, output hash) match expected values from escrow metadata

Security Note:

Proof verification is currently a stub implementation. Production systems must integrate real cryptographic verification for ZK proofs, TEE attestations, and signature aggregation.

Refund Flows

If the service provider fails to deliver the service or submit a valid proof within the timeout period, the payer can claim a refund. Refunds return the escrowed funds to the payer's account minus any network fees already collected.

use tenzro_settlement::SettlementEngine;
use std::time::{Duration, SystemTime};

// Check if escrow is eligible for refund
let escrow = engine.get_settlement(&settlement_id).await?;

if escrow.created_at + Duration::from_secs(3600) < SystemTime::now() {
    // Timeout reached, payer can claim refund
    let refund_request = SettlementRequest {
        settlement_id: settlement_id.clone(),
        from: escrow.to.clone(), // Provider account (escrowed funds)
        to: escrow.from.clone(), // Payer account (refund destination)
        amount: escrow.amount,
        asset: escrow.asset.clone(),
        proof: Some(ServiceProof::Cryptographic {
            algorithm: "timeout_refund".to_string(),
            signature: vec![], // No signature needed for timeout
            public_key: vec![],
        }),
        metadata: serde_json::json!({
            "type": "timeout_refund",
            "original_settlement": settlement_id.to_hex(),
        }),
    };

    engine.settle(&refund_request).await?;
}

Dispute Resolution

For complex escrows involving multiple parties, Tenzro supports on-chain dispute resolution through governance proposals. Any party can submit evidence (ZK proofs, attestations, transaction logs) and request arbitration from validator nodes or designated arbiters.

use tenzro_token::GovernanceEngine;

// Submit dispute to governance
let governance = GovernanceEngine::new();
let proposal = governance.submit_proposal(
    "Escrow Dispute Resolution",
    format!("Settlement {} requires arbitration", settlement_id.to_hex()),
    serde_json::json!({
        "type": "escrow_dispute",
        "settlement_id": settlement_id.to_hex(),
        "evidence": {
            "provider_attestation": "0x...",
            "payer_claim": "Inference result incorrect",
        },
        "requested_action": "refund_payer"
    }),
).await?;

// Validators vote on dispute resolution
// If approved, governance contract executes refund or release

Network Fees

All escrow settlements are subject to a network fee (default 0.5%) which is collected by the FeeCollector and routed to the network treasury. Fees are calculated on the settlement amount and deducted before crediting the recipient.

// Fee calculation for 1 TNZO settlement
let amount = 1_000_000_000_000_000_000; // 1 TNZO (18 decimals)
let fee_bps = 50; // 0.5% = 50 basis points

let fee = (amount * fee_bps) / 10_000; // 5_000_000_000_000_000 (0.005 TNZO)
let net_amount = amount - fee; // 995_000_000_000_000_000 (0.995 TNZO)

// Provider receives net amount
// Treasury receives fee

Fees are essential for network sustainability, funding validator rewards, protocol development, and ecosystem grants. The fee percentage is governed by on-chain governance and can be adjusted through validator voting.

Integration with Identity

Escrow settlements integrate with Tenzro's TDIP (Tenzro Decentralized Identity Protocol) to enforce delegation scopes and payment limits for machine identities. When an AI agent initiates an escrow on behalf of a human, the settlement engine verifies:

  • Agent has valid did:tenzro:machine:* identity
  • Agent's delegation scope permits the operation type (e.g., "ai_inference_payment")
  • Settlement amount within max_transaction_value and max_daily_spend limits
  • Payment protocol (Direct/MPP/x402) is in allowed_payment_protocols
  • Chain ID matches allowed_chains
use tenzro_identity::{IdentityRegistry, DelegationScope};

// Verify agent can create escrow
let registry = IdentityRegistry::new();
let agent_did = "did:tenzro:machine:controller_abc:agent_xyz";
let agent = registry.resolve(agent_did).await?;

if let IdentityData::Machine { delegation_scope, .. } = &agent.data {
    // Check delegation limits
    assert!(amount <= delegation_scope.max_transaction_value);
    assert!(delegation_scope.allowed_operations.contains(&"ai_inference_payment".to_string()));
    assert!(delegation_scope.allowed_payment_protocols.contains(&PaymentProtocolId::Direct));
}

Storage and Persistence

Escrow state is persisted to RocksDB in the CF_SETTLEMENTS column family. Each settlement record includes:

  • Settlement ID (Hash)
  • Payer and payee addresses
  • Amount and asset type
  • Status (Pending/Released/Refunded/Failed)
  • Proof data (if submitted)
  • Metadata (service details, expected proof type)
  • Timestamps (created_at, released_at, timeout_at)

Finalized settlements (Released/Refunded) are synced to the blockchain with fsync durability to survive power loss.

Production Note:

Current implementation uses in-memory storage for micropayment channels and challenges. Production deployments must persist all escrow state to RocksDB to prevent fund loss on node restart.

Next Steps

Now that you understand escrow-based settlements, explore: