NonEvmAddress
Title: NonEvmAddress
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
Thin non-EVM addressing helper layered OVER the vendored OpenZeppelin ERC-7930
InteroperableAddress generic formatV1/parseV1 (which handle ANY chainType / chainReference /
address bytes). Down-converts a parsed ERC-7930 address field (<= 32 bytes) into a right-aligned
bytes32, and formats a full 32-byte non-EVM address back out. This is the epic-sequenced-first
foundation for bytes32 non-EVM remotes — e.g. the Circle CCTP mintRecipient down-convert, where
a 20-byte EVM recipient or a 32-byte non-EVM (Solana/Aptos/…) recipient must both land in a single
bytes32 slot.
Does NOT modify the vendored OZ library — it only composes its generic entrypoints. A 20-byte EVM
address ends in the low 20 bytes (bytes32(uint256(uint160(addr)))); a 32-byte non-EVM address is
returned verbatim. Starknet felt252 addressing (which needs a Stark-field range check the raw
bytes32 down-convert does not perform) is layered on top via parseV1ToFelt252.
Constants
STARKNET_CHAIN_TYPE
The CASA/CAIP-350 ERC-7930 ChainType binary key for the starknet namespace.
Derivation: the ChainAgnostic namespaces registry (ChainAgnostic/namespaces,
starknet/caip350.md) assigns the starknet CAIP-104 namespace the ChainType binary key 0x0003
(eip-155 = 0x0000). The chain reference is the UTF-8 bytes of the Starknet chain-id string
(SN_MAIN = 0x534e5f4d41494e); the address is the raw 32-byte big-endian felt252.
bytes2 internal constant STARKNET_CHAIN_TYPE = 0x0003;FIELD_PRIME
The Stark field prime 2**251 + 17 * 2**192 + 1. Every Starknet felt252 (address, selector,
payload element) MUST be strictly below this value.
uint256 internal constant FIELD_PRIME = 0x0800000000000011000000000000000000000000000000000000000000000001;Functions
parseV1ToBytes32
Parses a generic ERC-7930 (version 1) interoperable address and right-aligns its address field
into a bytes32.
Reverts NonEvmAddressTooLong if the address field is longer than 32 bytes. The right-align shift
discards the (potentially dirty) trailing bytes of the bytes memory word, so no masking is needed.
function parseV1ToBytes32(bytes memory self)
internal
pure
returns (bytes2 chainType, bytes memory chainReference, bytes32 addr);Parameters
| Name | Type | Description |
|---|---|---|
| self | bytes | The full ERC-7930 interoperable address bytes. |
Returns
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | The 2-byte ERC-7930 chain type (0x0000 = eip-155). |
| chainReference | bytes | The raw chain-reference bytes (e.g. the EVM chainId, big-endian). |
| addr | bytes32 | The address field right-aligned into a bytes32: a 20-byte EVM address occupiesthe low 20 bytes; a 32-byte non-EVM address fills the whole word. |
parseV1ToFelt252
Parses a generic ERC-7930 (version 1) interoperable address whose address field is a Starknet
felt252, range-checking it against the Stark field prime.
Wraps parseV1ToBytes32 (so all its canonical-width rules apply — including the eip-155 20-byte
rule, which stays untouched), then enforces felt < FIELD_PRIME (revert NonEvmAddressNotAFelt)
and felt != 0 (revert NonEvmAddressZeroFelt). The caller is responsible for checking the
chainType/chainReference against its expected Starknet chain.
function parseV1ToFelt252(bytes memory self)
internal
pure
returns (bytes2 chainType, bytes memory chainReference, uint256 felt);Parameters
| Name | Type | Description |
|---|---|---|
| self | bytes | The full ERC-7930 interoperable address bytes. |
Returns
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | The 2-byte ERC-7930 chain type (0x0003 = starknet, see STARKNET_CHAIN_TYPE). |
| chainReference | bytes | The raw chain-reference bytes (UTF-8 chain-id string, e.g. SN_MAIN). |
| felt | uint256 | The address field as a validated felt252 (0 < felt < FIELD_PRIME). |
formatV1
Convenience over the generic InteroperableAddress.formatV1 for a FULL 32-byte non-EVM address.
function formatV1(bytes2 chainType, bytes memory chainReference, bytes32 addr)
internal
pure
returns (bytes memory);Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | The 2-byte ERC-7930 chain type. |
| chainReference | bytes | The chain-reference bytes. |
| addr | bytes32 | The full 32-byte non-EVM address. |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes | The ERC-7930 (version 1) interoperable address bytes with a 32-byte address field. |
Errors
NonEvmAddressTooLong
The parsed ERC-7930 address field exceeds the 32-byte bytes32 capacity.
error NonEvmAddressTooLong(uint256 length);Parameters
| Name | Type | Description |
|---|---|---|
| length | uint256 |
NonEvmAddressEmpty
The parsed address field was empty (would right-align to bytes32(0)).
error NonEvmAddressEmpty();NonEvmAddressInvalidEvmWidth
An eip-155 (EVM) address field was not the canonical 20 bytes — rejecting it prevents a malformed short address from silently right-aligning into a WRONG bytes32 (irreversible for a token mint).
error NonEvmAddressInvalidEvmWidth(uint256 length);Parameters
| Name | Type | Description |
|---|---|---|
| length | uint256 |
NonEvmAddressNotAFelt
The parsed address field is not a valid Starknet felt252 (value >= FIELD_PRIME).
error NonEvmAddressNotAFelt(uint256 value);Parameters
| Name | Type | Description |
|---|---|---|
| value | uint256 |
NonEvmAddressZeroFelt
The parsed address field decodes to the zero felt (no valid Starknet contract lives at 0).
error NonEvmAddressZeroFelt();