How to Perform Hex Conversion in GenLayer Contracts: Address API Guide

GenLayer contracts use the Address type to handle wallet addresses, providing the Address(hex_str) constructor and addr.as_hex property to convert between raw bytes and EIP-55-checksummed hex strings.

The GenLayer Project Boilerplate demonstrates the standard patterns for hex conversion when working with contract addresses. Understanding these patterns is essential for passing addresses between contracts, returning values to UIs, and writing reliable tests.

Understanding the Address Type

GenLayer's native Address type stores wallet addresses internally as 20-byte values. The type is defined in the platform's Python runtime and exposed through the genlayer package.

Constructor Options

You can create an Address instance from two input formats:

Input Constructor Call Result
Hex string Address("0x1234...") Parsed and validated Address
Raw bytes Address(b'\x12\x34...') 20-byte Address instance

In contracts/football_bets.py, the get_points method accepts an Address parameter directly. The implementation wraps incoming values with Address(player_address) to ensure proper typing:

@gl.public.view
def get_points(self, player_address: Address) -> u256:
    # Access stored points using the Address instance directly

    return self.points.get(Address(player_address), 0)

This pattern handles both hex string and raw byte inputs gracefully.

Converting Address to Hex String

The addr.as_hex property returns the EIP-55-checksummed hexadecimal representation with the 0x prefix. This is the correct method for producing human-readable addresses.

In contracts/football_bets.py at lines 111-115, the contract returns a dictionary with hex keys for UI consumption:

@gl.public.view
def get_bets(self) -> dict:
    # Return a mapping where keys are hex strings for UI consumption

    return {k.as_hex: v for k, v in self.bets.items()}

Critical Gotcha: Avoid str(addr)

The str() built-in does not produce a hex string. As documented in tests/direct/test_patterns.py at lines 189-195, str(addr) yields the raw bytes representation (e.g., b'\x12\xab...'), which is not valid for address comparison or display.

To obtain hex output, always use:

  • addr.as_hex — checksummed hex string with 0x prefix
  • "0x" + addr.hex() — manual construction (equivalent to above)

Converting Address to Raw Bytes

For low-level operations, extract the underlying 20-byte value using either:

  • bytes(addr) — Python's bytes() constructor
  • addr.bytes — direct property access

These yield identical results suitable for cryptographic operations or storage in byte-oriented data structures.

Helper Utilities for Testing

The test suite in tests/direct/conftest.py provides a robust to_hex helper function used across direct-mode tests:

def to_hex(addr_bytes):
    """Convert address bytes to a checksummed hex string matching contract output."""
    if hasattr(addr_bytes, "as_hex"):
        return addr_bytes.as_hex        # Already an Address object

    return Address(addr_bytes).as_hex   # Raw bytes → Address → hex

This helper normalizes both Address objects and raw bytes to consistent hex strings. Tests in tests/direct/test_views.py at lines 5-6 demonstrate its usage for assertions against contract-returned values:


# Example test assertion pattern

expected_hex = to_hex(direct_alice)
assert contract_result == expected_hex

Complete Working Example

Here's a full contract demonstrating input and output hex conversion patterns:

import genlayer as gl
from genlayer.types import Address, u256, TreeMap

class TokenTracker(gl.Contract):
    balances: TreeMap[Address, u256]
    
    @gl.public.write
    def register(self, user_hex: str) -> None:
        """Accept hex string, store as Address."""
        addr = Address(user_hex)
        self.balances[addr] = 0
    
    @gl.public.view
    def get_balance_hex(self, user_hex: str) -> u256:
        """Accept hex string, return balance."""
        addr = Address(user_hex)
        return self.balances.get(addr, 0)
    
    @gl.public.view
    def list_holders(self) -> list[str]:
        """Return all holder addresses as hex strings."""
        return [addr.as_hex for addr in self.balances.keys()]

Quick Reference Table

Operation Method Returns
Hex string → Address Address("0x...") Address instance
Raw bytes → Address Address(b'...') Address instance
Address → hex string addr.as_hex "0x..." string
Address → raw bytes bytes(addr) or addr.bytes 20-byte bytes
Address → str (avoid) str(addr) b'...' representation

Summary

  • Use Address(hex_str) to convert incoming hex strings to the native type.
  • Use addr.as_hex to output checksummed hex strings for UIs and APIs.
  • Never use str(addr) for hex conversion—it returns raw bytes representation.
  • Reference tests/direct/conftest.py for the to_hex helper pattern in your own test suites.
  • Follow contracts/football_bets.py for production-ready address handling patterns.

Frequently Asked Questions

How do I convert a user's wallet address from a frontend string to a GenLayer Address?

Use the Address constructor directly: addr = Address("0x742d35Cc..."). The constructor accepts any valid EIP-55-checksummed hex string and returns a properly typed Address instance ready for storage or contract calls.

Why does str(addr) not return a hex string in GenLayer contracts?

GenLayer's Address type inherits Python's default object string representation, which displays the underlying raw bytes as a bytes literal (e.g., b'\x12\xab...'). This design prevents accidental hex conversion without explicit checksum validation. Always use addr.as_hex for intentional hex output.

How can I test that my contract returns the correct address?

Use the to_hex helper from tests/direct/conftest.py or replicate its pattern: check if the value has .as_hex, otherwise wrap with Address() first. This normalizes both Address objects and raw bytes to comparable hex strings in your assertions.

Does GenLayer support lowercase or non-checksummed hex strings?

The Address constructor accepts standard hex strings and normalizes them to EIP-55 checksum format. Outputs via addr.as_hex are always properly checksummed, ensuring consistency across contract interactions and reducing the risk of address confusion errors.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →