# Why TinyWallet-Bus Rejects Uppercase 0X EVM Prefixes

> Discover why TinyWallet-Bus rejects uppercase 0X EVM prefixes. Learn how ethers_core::types::Address::from_str handles prefixes and causes validation failures.

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

---

**TinyWallet-Bus rejects uppercase "0X" EVM prefixes because its `validate_ethereum_address` function delegates parsing to `ethers_core::types::Address::from_str`, which only strips the lowercase "0x" prefix before decoding, causing uppercase variants to fail validation.**

The **OpenHuman** project's TinyWallet-Bus crate enforces strict formatting rules for Ethereum addresses submitted to its wallet API. When validating an address, the library specifically rejects any string beginning with an uppercase **"0X"** prefix, even when the subsequent hexadecimal characters are valid. This behavior stems from the underlying parsing logic inherited from the `ethers-rs` ecosystem, which enforces a canonical lowercase prefix representation.

## How TinyWallet-Bus Validates Ethereum Addresses

In [`vendor/tinywallet-bus/src/validation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinywallet-bus/src/validation.rs) (lines 27-38), the `validate_ethereum_address` function serves as the entry point for all address validation within the OpenHuman wallet contract. Rather than implementing custom parsing logic, this wrapper delegates directly to the standard **Ethers-Core** parser:

```rust
// vendor/tinywallet-bus/src/validation.rs
pub fn validate_ethereum_address(s: &str) -> Result<Address, ValidationError> {
    ethers_core::types::Address::from_str(s)
        .map_err(|e| ValidationError::InvalidFormat(e.to_string()))
}

```

This delegation means TinyWallet-Bus inherits the strict prefix requirements defined in the upstream `ethers_core::types::Address::from_str` implementation, as utilized in the OpenHuman integration layer at [`src/openhuman/web3/wallet.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet.rs).

## The Root Cause: Case-Sensitive Prefix Stripping in Ethers-Core

The rejection occurs in the external dependency `ethers-core`, specifically within [`src/address.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/address.rs) (lines 50-61). The parser checks for the prefix using a case-sensitive comparison that only recognizes the lowercase **"0x"** string:

```rust
// ethers-core/src/types/address.rs (lines 50-61)
if s.starts_with("0x") {
    // Strip lowercase prefix and decode hex
} else {
    // Any other prefix, including "0X", triggers InvalidPrefix error
    Err(ParseHexError::InvalidPrefix)
}

```

Because the `starts_with("0x")` check is case-sensitive, an address beginning with **"0X"** bypasses the prefix-stripping logic. The subsequent hex-decode step then encounters the literal "0X" characters, fails to parse them as hexadecimal digits, and returns an error that TinyWallet-Bus propagates as a validation failure.

## Practical Code Examples: Testing Address Validation

When integrating TinyWallet-Bus into your application, passing an address with an uppercase prefix results in immediate rejection, while the lowercase variant succeeds:

```rust
use tinywallet_bus::validation::validate_ethereum_address;

fn main() {
    // ✅ Accepted – lowercase prefix (valid)
    assert!(validate_ethereum_address(
        "0x1234abcd5678ef901234abcd5678ef901234abcd"
    ).is_ok());

    // ❌ Rejected – uppercase prefix (invalid)
    assert!(validate_ethereum_address(
        "0X1234ABCD5678EF901234ABCD5678EF901234ABCD"
    ).is_err());
}

```

This strict validation applies consistently across the OpenHuman codebase. The wallet integration at [`src/openhuman/web3/wallet.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet.rs) relies on TinyWallet-Bus for all EVM address processing, inheriting these case-sensitive requirements.

## Summary

- TinyWallet-Bus delegates all address parsing to `ethers_core::types::Address::from_str` via [`vendor/tinywallet-bus/src/validation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinywallet-bus/src/validation.rs) (lines 27-38).
- The underlying parser only accepts the lowercase **"0x"** prefix, rejecting uppercase **"0X"** variants.
- Case-sensitive prefix matching in [`ethers-core/src/types/address.rs`](https://github.com/tinyhumansai/openhuman/blob/main/ethers-core/src/types/address.rs) (lines 50-61) causes validation failures for non-canonical formats.
- This behavior enforces a single, unambiguous address representation throughout the OpenHuman wallet API.

## Frequently Asked Questions

### Does TinyWallet-Bus accept any uppercase letters in Ethereum addresses?

While the **"0X"** prefix is strictly rejected, the hexadecimal characters following a valid **"0x"** prefix may contain uppercase letters depending on the checksum implementation. However, the prefix itself must always be lowercase to pass initial validation in [`vendor/tinywallet-bus/src/validation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinywallet-bus/src/validation.rs).

### Is this rejection of 0X a bug or intentional design?

This is **intentional**. The design enforces a canonical representation for EVM addresses throughout the OpenHuman codebase, preventing ambiguities that could arise from mixed-case prefixes and ensuring consistent address handling across the wallet API.

### How can I normalize addresses to avoid rejection?

Normalize user input by converting the first two characters to lowercase before validation, or use a standard library function that ensures the **"0x"** prefix conforms to the expected format prior to calling `validate_ethereum_address`.

### Which files handle the validation logic in the OpenHuman repository?

The primary validation wrapper resides in [`vendor/tinywallet-bus/src/validation.rs`](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinywallet-bus/src/validation.rs), which is consumed by the integration layer in [`src/openhuman/web3/wallet.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/web3/wallet.rs). The actual parsing rules are defined in the external [`ethers-core/src/types/address.rs`](https://github.com/tinyhumansai/openhuman/blob/main/ethers-core/src/types/address.rs) dependency (lines 50-61).