# Division of Responsibilities Between the tinywallet-bus Contract and the Host

> Understand the division of responsibilities between the tinywallet-bus contract and the OpenHuman host. Learn how the contract handles static vocabulary and validation while the host manages network operations and policy enforc...

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: architecture
- Published: 2026-08-28

---

**The tinywallet-bus contract defines static vocabulary and pure validation logic, while the OpenHuman host handles all runtime network operations, endpoint resolution, and policy enforcement.**

The `tinywallet-bus` crate in the `tinyhumansai/openhuman` repository implements a **wire contract** pattern that strictly separates portable domain logic from heavy infrastructure dependencies. This division of responsibilities between the tinywallet-bus contract and the host ensures that modules remain lightweight and compilable without pulling in networking crates, while the host retains full control over transport policies, secret handling, and fail-over semantics.

## Core Architectural Split: Contract vs. Host

The architecture follows a strict **"what" versus "how"** separation. The contract defines data shapes and pure functions, while the host provides the runtime environment that executes I/O operations.

- **Contract side (`tinywallet-bus`)**: Contains only static definitions, constants, and pure logic. It compiles without `tokio`, `reqwest`, or cryptographic networking libraries.
- **Host side (OpenHuman core)**: Implements the `Transport` trait, resolves RPC endpoints, handles retries, and manages secrets. This is where all async I/O and network-specific error handling occurs.

This split allows the `tinywallet-bus` crate (located at `vendor/tinywallet/crates/tinywallet-bus`) to serve as a domain vocabulary that any TinyWallet module can import without bloating its dependency tree.

## Responsibilities of the tinywallet-bus Contract

### Static Vocabulary and Constants

The contract houses all **RPC method identifiers** and **member constants** used across the TinyWallet domain. These are defined in the `methods` module and other constant tables, ensuring consistent naming between modules and hosts. As documented in [`AGENTS.md`](https://github.com/tinyhumansai/openhuman/blob/main/AGENTS.md) (lines 263-267), this vocabulary is shared with any TinyWallet module through the contract crate.

### Serializable Request and Response Types

All **EIP-712 payloads**, **ERC-20 calldata definitions**, and **address validation structs** live in the contract. These types are serializable and provide the data schemas that the host will eventually transmit over the wire. They define the shape of network requests without performing any actual network operations.

### Pure Validation Helpers

The contract provides **I/O-free validation functions** that check address formats and data integrity. For example, Bitcoin address validation resides in `tinywallet_bus::address::btc::validate`, which performs P2WPKH format checks without external dependencies. Host code in [`src/openhuman/web3/wallet/chains/btc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/chains/btc.rs) (lines 63-84) invokes these pure functions to validate inputs before network transmission.

## Responsibilities of the OpenHuman Host

### Transport Abstraction and Network Handling

The host implements the **`Transport` trait** defined in the contract, providing the concrete `OpenHumanTransport` struct in [`src/openhuman/web3/wallet/transport.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/transport.rs). This implementation maps `NetworkId` values to HTTP endpoints, executes JSON-RPC calls, and manages the shared HTTP client. Unlike the contract, the host code is fully async and depends on heavy crates like `reqwest` and `tokio`.

### Endpoint Resolution and Failover Logic

When a module requests a network operation, the host performs **endpoint resolution** through the `resolve` function and `rpc_url_for_*` helpers. It applies environment overrides, selects fallback Solana endpoints, and manages the fail-over chain. This runtime decision-making stays entirely within the host's [`transport.rs`](https://github.com/tinyhumansai/openhuman/blob/main/transport.rs) module, keeping the contract agnostic of specific RPC URLs or deployment environments.

### Security and Error Classification

The host handles **URL redaction** via the `redact_rpc_url` helper to prevent API keys from appearing in logs. It also classifies transport failures through the `classify` function, distinguishing between retryable network errors and authoritative RPC failures. This classification feeds into OpenHuman's retry semantics and fail-over logic, ensuring robust error handling that remains invisible to the contract layer.

## Implementation Examples

The following examples demonstrate how the contract and host interact in practice.

First, the contract provides pure address validation:

```rust
// Contract side: tinywallet-bus
use tinywallet_bus::address::btc;

// Returns Ok(addr) if valid main-net P2WPKH
pub fn validate_btc_address(addr: &str) -> Result<String, String> {
    tinywallet_bus::address::btc::validate(addr)
        .map_err(|e| e.to_string())
}

```

The host implements the transport interface that actually performs the network call:

```rust
// Host side: src/openhuman/web3/wallet/transport.rs
use tinywallet_bus::rpc::{NetworkId, Transport, TransportResult};

#[derive(Debug, Clone, Copy, Default)]
pub struct OpenHumanTransport;

#[async_trait::async_trait]
impl Transport for OpenHumanTransport {
    async fn json_rpc(
        &self,
        network: NetworkId,
        method: &str,
        params: serde_json::Value,
    ) -> TransportResult<serde_json::Value> {
        // Resolve concrete RPC URL
        let url = resolve(network)?;
        // Perform HTTP call using OpenHuman's client
        rpc_call_to::<Value>(&url, method, params)
            .await
            .map_err(|msg| classify(network, msg))
    }
}

```

Finally, host code combines both layers—using contract validation before host transport:

```rust
// Host side: using contract and transport together
let addr = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8c9".to_string();
let validated = validate_btc_address(&addr)?;  // contract validation

let network = tinywallet_bus::NetworkId::chain(tinywallet_bus::Chain::Btc);
let transport = OpenHumanTransport::default();

let result = transport
    .json_rpc(network, "getBalance", json!({ "address": validated }))
    .await?;

```

## Summary

- **tinywallet-bus** acts as the wire contract, containing only static vocabulary, serializable types, and pure validation logic without I/O dependencies.
- **OpenHuman host** implements all runtime logic including the `Transport` trait, endpoint resolution, URL redaction, and error classification in [`src/openhuman/web3/wallet/transport.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/transport.rs).
- Host code delegates to contract functions for input validation (e.g., `tinywallet_bus::address::btc::validate`) before performing network operations.
- This separation allows modules to compile without heavy networking crates (`reqwest`, `tokio`, crypto libraries), while the host retains full control over network policies and secret handling.
- Transaction assembly and broadcasting occur in host modules like [`src/openhuman/web3/wallet/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/ops.rs) and `src/openhuman/web3/wallet/chains/`, utilizing contract-defined data structures.

## Frequently Asked Questions

### What is the purpose of the tinywallet-bus contract?

The tinywallet-bus contract serves as a portable **domain vocabulary** that defines RPC method names, request/response types, and pure validation helpers. It allows TinyWallet modules to share consistent data structures without importing heavy networking or cryptographic dependencies, ensuring the module remains lightweight and compilable in constrained environments.

### How does the host implement the Transport trait?

The host provides the `OpenHumanTransport` struct in [`src/openhuman/web3/wallet/transport.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/transport.rs) that implements the `Transport` trait defined in the contract. This implementation handles concrete HTTP operations, endpoint resolution via the `resolve` function, and error classification through the `classify` function, bridging the contract's abstract network interface with OpenHuman's actual RPC infrastructure.

### Why separate pure validation from network operations?

Separating pure validation from I/O allows the contract to perform **address format checks** and data validation without depending on async runtimes or network libraries. This design keeps the contract crate dependency-free and portable, while the host handles the mutable, async, and fallible aspects of network communication separately.

### Where is endpoint resolution logic located?

Endpoint resolution and fail-over logic reside entirely within the host codebase, specifically in [`src/openhuman/web3/wallet/transport.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet/transport.rs). The `resolve` function and `rpc_url_for_*` helpers determine the correct RPC URL for a given `NetworkId`, apply environment-specific overrides, and manage fallback endpoints, keeping the contract layer agnostic of deployment-specific configuration.