RADIX WikiRADIX Wiki

Introduction

On most ledgers an address is an opaque hash: nothing in it tells you whether you are looking at a wallet, a token, or a contract, and nothing tells you which network it belongs to. A Radix address states both in plain text before you decode a single byte. account_rdx12... is an account on mainnet; resource_tdx_2_1t... is a token on Stokenet.

That is not cosmetic. The Bech32m human-readable prefix carries two independent facts β€” the entity type and the network β€” and the decoder cross-checks the prefix against the type byte inside the payload, so an address that claims to be one kind of thing and encodes another is rejected rather than misread. This page describes the format as the ledger actually implements it, citing radix-common/src/address rather than prose documentation.

Addresses are the values you put in a transaction manifest, and the Radix Engine Toolkit is what encodes and decodes them off-ledger.

Anatomy of an Address

Every global address is a Bech32m string in three parts:

account_rdx12y02de8ma5jz9pxkvgzr7g5v4g7hd44rvz4ynqvz3xy4cqe4vw6a2j
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       HRP     β”‚                      payload
            separator
  • HRP β€” <entity>_<network suffix>, assembled by HrpSet from the NetworkDefinition's hrp_suffix. There is one HRP per entity class per network.
  • 1 β€” the Bech32 separator. It cannot appear in the payload, so the last 1 in the string always marks the boundary.
  • Payload β€” the entity's node id in base-32, ending in a six-character checksum. The first decoded byte is the entity type discriminant.

AddressBech32Decoder performs three checks in order: the string must decode as Bech32m specifically (plain Bech32 is rejected with InvalidVariant), the first payload byte must map to a known EntityType, and the HRP actually present must equal the HRP that entity type is supposed to carry on this network β€” otherwise InvalidHrp. The last check is the one that matters for integrations: a well-formed address for the wrong network, or a resource address relabelled as a component, fails to decode rather than resolving to something unexpected.

Entity Prefixes

The HRP entity component is fixed per class of addressable thing. These are the global entities β€” the ones that appear in manifests and block explorers:

PrefixEntityType byte
package_Package β€” published blueprint code13
resource_Resource manager β€” fungible (93) or non-fungible (154)93 / 154
component_Generic (Scrypto) component instance192
account_Account β€” allocated (193) or preallocated (209 / 81)193 / 209 / 81
identity_Identity β€” backs Personas194 / 210 / 82
validator_Validator131
consensusmanager_Consensus Manager β€” one per network134
transactiontracker_Transaction Tracker β€” one per network130
accesscontroller_Access Controller195
pool_Pool β€” one-, two-, or multi-resource196–198
locker_Account Locker104

Type bytes are the u8 discriminants of the EntityType enum. The source file notes that this table is mirrored in REP-60 and that prefix values are allocated under REP-71 β€” so the numbers are a deliberate, versioned assignment, not incidental ordering.

Why the First Payload Characters Are Readable

The discriminants are chosen so that the base-32 encoding of the type byte spells a mnemonic. Each payload character carries five bits: the entity byte's top five bits select the first character outright, and its bottom three bits constrain the second to one of four.

So GlobalValidator = 0b10000011 gives 10000 β†’ s (system) and 011 β†’ one of v, d, w, 0. Every validator address on the network therefore begins validator_rdx1s followed by one of those four characters β€” which holds for all 188 registered mainnet validators at epoch 330462. The families are:

  • p β€” package Β· c β€” standard global component (account, identity, access controller, pool) Β· d β€” account locker
  • s β€” system component (consensus manager, validator, transaction tracker)
  • t β€” fungible ("token") resource and vault Β· n β€” non-fungible resource and vault
  • 6 β€” preallocated Secp256k1 entity Β· 2 β€” preallocated Ed25519 entity
  • l β€” internal component Β· k β€” internal key-value store

The well-known native addresses go further and use vanity payloads, which is why the faucet reads component_rdx1cpt...faucet and XRD reads resource_rdx1tkn...radxrd. For ordinary entities only the first two characters are predictable; the rest is the node id.

Network Specifiers

The suffix after the entity name is the network's hrp_suffix, defined alongside its numeric id in NetworkDefinition:

NetworkIdSuffixExample
Mainnet1rdxaccount_rdx1...
Stokenet2tdx_2_account_tdx_2_1...
Localnet240locaccount_loc1...
Simulator (resim)242simaccount_sim1...

The retired testnets keep their reservations β€” adapanet (10, tdx_a_), nebunet (11, tdx_b_), and the three RCnet generations kisharnet (12, tdx_c_), ansharnet (13, tdx_d_) and zabanet (14, tdx_e_) β€” so addresses captured from those networks still decode as historical artefacts and can never be confused with mainnet.

Telling networks apart. A recurring question is how to check whether a component or package is on Stokenet or mainnet. There is no on-ledger flag to query, because an address is only meaningful within the network that issued it: the suffix is the answer. Compare the network suffix rather than pattern-matching the whole prefix β€” account_rdx and account_tdx_2_ share the leading account_, and a naive startsWith on the entity name alone will match both. Decode the address instead and read the network back, which is what the Radix Engine Toolkit does; the Gateway you point at is itself network-specific, so a mismatched address simply will not resolve.

Global and Internal Entities

EntityType splits every entity into global and internal, and the HRP reflects the split. Global entities are independently addressable and can be called from a manifest. Internal entities are owned by exactly one parent and reached only through it, so they carry an internal_ HRP:

  • internal_vault_ β€” a fungible or non-fungible vault inside a component or account
  • internal_component_ β€” a component instance owned by another component
  • internal_keyvaluestore_ β€” a key-value store, whose substates are treated as independent for contention and versioning

This is the addressing-level view of the substate model: a vault holding your XRD has a real address, but you cannot call it directly β€” you go through the account that owns it. Seeing an internal_vault_ address in a transaction receipt where you expected a resource_ address usually means you read a balance-change entry instead of the resource itself.

Preallocated Addresses

Most accounts on Radix were never created by a transaction. A preallocated (formerly "virtual") account or identity address is derived deterministically from a public key, so it is a valid destination before anything exists at it on-ledger; the account component is instantiated the first time it is used.

The signature scheme is part of the entity type, which makes it visible in the address:

  • GlobalPreallocatedEd25519Account (81) β†’ account_rdx12... β€” the scheme the Radix Wallet uses for accounts created on Babylon
  • GlobalPreallocatedSecp256k1Account (209) β†’ account_rdx16... β€” including accounts carried over from Olympia
  • GlobalAccount (193) β†’ account_rdx1c... β€” an account allocated by a transaction rather than derived from a key

The same three-way split applies to identities (82, 210, 194). The practical consequence: the second character of an account address tells you which curve secures it, before any ledger lookup. Deriving these addresses is a Radix Engine Toolkit function, not a Gateway call β€” it is pure computation over the public key.

Transaction Identifiers

The same HRP scheme covers the parts of a transaction, which is why a transaction id is self-describing in a log or an explorer URL:

txid_Transaction intent hash β€” the id you poll the Gateway with
signedintent_Signed transaction intent
notarizedtransaction_Notarized transaction β€” what is actually submitted
subtxid_Subintent hash, introduced with Transaction V2
ledgertransaction_Ledger transaction hash
roundupdatetransaction_Round update β€” consensus-generated, not user-submitted
systemtransaction_System transaction, e.g. genesis and protocol updates

These are hashes rather than addressable entities, so they carry no entity-type byte, but they take the network suffix β€” a txid_tdx_2_ is a Stokenet transaction. The distinction between the three intent-stage hashes matters when tracking a transaction: the intent hash is stable from the moment the intent is built, which is what makes it usable as an idempotency key. The full sequence is covered in Transaction Lifecycle.

Well-Known Addresses

Native entities are allocated fixed node ids in native_addresses.rs, so their addresses are constants you can hardcode. The payload is identical on every network; only the HRP changes:

XRDresource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd
Consensus Managerconsensusmanager_rdx1scxxxxxxxxxxcnsmgrxxxxxxxxx000999665565xxxxxxxxxcnsmgr
Transaction Trackertransactiontracker_rdx1stxxxxxxxxxxtxtrakxxxxxxxxx006844685494xxxxxxxxxtxtrak
Faucet (testnets)component_rdx1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxfaucet
Account packagepackage_rdx1pkgxxxxxxxxxaccntxxxxxxxxxx000929625493xxxxxxxxxaccntx

The XRD address above was confirmed against mainnet, not just read from source. The faucet is the clearest illustration of the network-suffix rule: the same component is component_tdx_2_1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxfaucet on Stokenet, where it will actually dispense test XRD.

Alongside these sit the native badge resources whose non-fungible ids stand in for authority rather than assets β€” the virtual signature badges resource_rdx1nfxxxxxxxxxxed25sgxxxxxxxxx002236757237xxxxxxxxxed25sg and its secpsg counterpart, plus package, validator and account owner badges. They are ordinary badges as far as access rules are concerned, which is how "the signer of this transaction" becomes something a rule can name.

Working With Addresses

Three failure modes account for most address bugs in integrations:

  • String matching instead of decoding. Checking startsWith("account_rdx") looks safe until a Stokenet address arrives, and it tells you nothing about whether the checksum is valid. Decode and inspect the returned EntityType.
  • Assuming Bech32. Radix uses Bech32m, and generic Bech32 libraries in encode mode will produce a checksum the decoder rejects. Confirm the variant your library emits.
  • Treating a resource address as a component address. They are structurally interchangeable strings but different entity classes; the decoder will catch the swap, the Gateway will return nothing useful, and a manifest built on it fails static validation.

Static validation in the Radix Engine Toolkit catches all three locally, without a network round trip. For reading state at an address once you trust it, see Radix APIs; for putting addresses into transactions, see Transaction Manifest Language.