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 with0xprefix"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'sbytes()constructoraddr.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_hexto output checksummed hex strings for UIs and APIs. - Never use
str(addr)for hex conversion—it returns raw bytes representation. - Reference
tests/direct/conftest.pyfor theto_hexhelper pattern in your own test suites. - Follow
contracts/football_bets.pyfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →