---
title: "5. Addresses and Entity Types"
path: "/developers/transactions/05-addresses-and-entity-types"
version: "1.0.0"
author: "Hydrate"
createdAt: "2026-07-30T03:11:12.589Z"
updatedAt: "2026-07-30T03:11:12.589Z"
---

# 5. Addresses and Entity Types

<Infobox>
| Encoding | [Bech32m](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) (BIP-350) |
| Structure | `<entity>_<network>` + `1` + payload |
| First payload byte | Entity type discriminant |
| Mainnet suffix | `rdx` (network id 1) |
| Stokenet suffix | `tdx_2_` (network id 2) |
| Source of truth | [radix-common/src/address](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address/hrpset.rs) |
</Infobox>

## 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](https://docs.radixdlt.com/docs/network-gateway).

That is not cosmetic. The [Bech32m](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) 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](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address) rather than prose documentation.

Addresses are the values you put in a [transaction manifest](/developers/transactions/01-manifest-language), and the [Radix Engine Toolkit](/developers/transactions/04-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](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address/hrpset.rs) from the [NetworkDefinition](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/network/mod.rs)'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](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address/decoder.rs) 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:

| **Prefix** | **Entity** | **Type byte** |
| `package_` | [Package](/contents/tech/core-concepts/blueprints-and-packages) — published blueprint code | 13 |
| `resource_` | [Resource](/contents/tech/core-concepts/resources) manager — fungible (93) or non-fungible (154) | 93 / 154 |
| `component_` | Generic (Scrypto) component instance | 192 |
| `account_` | [Account](/contents/tech/core-protocols/smart-accounts) — allocated (193) or preallocated (209 / 81) | 193 / 209 / 81 |
| `identity_` | [Identity](/contents/tech/core-protocols/personas) — backs Personas | 194 / 210 / 82 |
| `validator_` | [Validator](/contents/tech/core-concepts/validator-nodes) | 131 |
| `consensusmanager_` | [Consensus Manager](/contents/tech/core-concepts/consensus-manager) — one per network | 134 |
| `transactiontracker_` | [Transaction Tracker](/contents/tech/core-concepts/transaction-tracker) — one per network | 130 |
| `accesscontroller_` | [Access Controller](/contents/tech/core-concepts/access-controller) | 195 |
| `pool_` | [Pool](/contents/tech/core-concepts/radix-pools) — one-, two-, or multi-resource | 196–198 |
| `locker_` | [Account Locker](/contents/tech/core-concepts/locker-blueprint) | 104 |

Type bytes are the `u8` discriminants of the [EntityType](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/types/entity_type.rs) 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](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/network/mod.rs):

| **Network** | **Id** | **Suffix** | **Example** |
| Mainnet | 1 | `rdx` | `account_rdx1...` |
| [Stokenet](/contents/tech/releases/stokenet) | 2 | `tdx_2_` | `account_tdx_2_1...` |
| Localnet | 240 | `loc` | `account_loc1...` |
| Simulator (`resim`) | 242 | `sim` | `account_sim1...` |

The retired testnets keep their reservations — adapanet (10, `tdx_a_`), nebunet (11, `tdx_b_`), and the three [RCnet](/contents/tech/releases/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](/developers/transactions/04-radix-engine-toolkit) does; the [Gateway](https://docs.radixdlt.com/docs/network-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](/contents/tech/core-concepts/buckets-proofs-and-vaults) 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](/contents/tech/core-concepts/substate-model): a vault holding your XRD has a real address, but you cannot call it directly — you go through the [account](/contents/tech/core-protocols/smart-accounts) 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](/contents/tech/releases/radix-mainnet-babylon)

- `GlobalPreallocatedSecp256k1Account` (209) → `account_rdx16...` — including accounts carried over from [Olympia](/contents/tech/releases/radix-mainnet-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](/contents/tech/core-protocols/personas) (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](/contents/tech/core-concepts/subintents-and-pre-authorizations) 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](/developers/transactions/02-transaction-lifecycle).

## Well-Known Addresses

Native entities are allocated fixed node ids in [native_addresses.rs](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/constants/native_addresses.rs), so their addresses are constants you can hardcode. The payload is identical on every network; only the HRP changes:

| [XRD](/contents/tech/core-protocols/xrd-token) | `resource_rdx1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxradxrd` |
| Consensus Manager | `consensusmanager_rdx1scxxxxxxxxxxcnsmgrxxxxxxxxx000999665565xxxxxxxxxcnsmgr` |
| Transaction Tracker | `transactiontracker_rdx1stxxxxxxxxxxtxtrakxxxxxxxxx006844685494xxxxxxxxxtxtrak` |
| Faucet (testnets) | `component_rdx1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxfaucet` |
| Account package | `package_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](/contents/tech/core-concepts/badges) as far as [access rules](/contents/tech/core-concepts/access-rules-and-auth-zones) 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](/developers/transactions/04-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](/developers/infrastructure/02-radix-apis); for putting addresses into transactions, see [Transaction Manifest Language](/developers/transactions/01-manifest-language).

## External Links

- [hrpset.rs — the HRP set for every entity and transaction part](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address/hrpset.rs)

- [entity_type.rs — EntityType discriminants and prefix derivations](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/types/entity_type.rs)

- [network/mod.rs — network ids and HRP suffixes](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/network/mod.rs)

- [decoder.rs — Bech32m validation and HRP cross-checking](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/address/decoder.rs)

- [native_addresses.rs — well-known native entity addresses](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-common/src/constants/native_addresses.rs)

- [BIP-350 — Bech32m specification](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)

- [Radix Engine Toolkit — Radix Documentation](https://docs.radixdlt.com/docs/radix-engine-toolkit)