Asynchronous Approval and Timeouts

## Asynchronous Approval and Timeouts

Because the App is a separate device, signing is inherently asynchronous. Your Product needs to tolerate the round-trip latency between the dispatch and the result.

Two failure modes are first-class and your Product UI should handle both:

- **User-initiated rejection**: The user dismissed the prompt on the App. From your Product's perspective, this should be treated like a cancellation. Return the user to a stable UI state and let them retry. The Product SDK surfaces this as `HostRejectedError`.
- **Session timeout**: The countdown reached zero before the user responded. From your Product's perspective, this is functionally identical to a rejection. Use the same response: stable UI, retry available. The Product SDK surfaces this as `TimeoutError`.

For the Product-side `try`/`catch` pattern, see [Sign and Submit Transactions](/apps/build/sign-and-submit/).

A practical UI consequence: do not freeze your interface for the duration of a sign request. The user may glance at their phone, get distracted, and approve later. Show a non-blocking pending state and make sure your retry path is idempotent in case the user attempts the same action twice.


Where to Go Next

## Where to Go Next

- Guide **Accounts and Signing**

    ---

    The Product-side how-to for building, signing, and submitting transactions, including the `try`/`catch` patterns for the failure modes documented above.

    [:octicons-arrow-right-24: Get Started](/apps/build/sign-and-submit/)

- Learn **Permissions**

    ---

    How `ChainSubmit` is declared in your Product manifest and how Desktop enforces it at the Host API boundary.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-desktop/permissions/)


Statement Store via Polkadot Desktop's Host API

Introduction

## Introduction

The Statement Store is a network-layer pub/sub primitive on Polkadot's People Chain for short-lived, gossiped, signed statements. Products do not talk to a Statement Store node directly; they go through Polkadot Desktop's Host API, which adds the things a Product on its own cannot do safely, including producing an authentication proof on the user's behalf, attaching the right account context, and applying the per-Product topic scope.

This page documents what Desktop adds when it mediates Statement Store traffic for a Product. The Statement Store itself (the pallet, the gossip layer, the lifecycle and validation rules) is documented separately in the [Statement Store infrastructure reference](/reference/apps/infrastructure/statement-store/). The Product-side how-to is the [Publish and Subscribe to Off-Chain Data](/apps/build/pub-sub-off-chain-data/) guide.


What Desktop Adds

## What Desktop Adds

A Product that calls `client.publish(...)` through the Product SDK is really doing this through Desktop:

- **Proof routing**: Every Statement Store submission carries an authentication proof. The Product does not produce the proof itself. It requests one through the Host API, and Desktop forwards the request to the paired App, which signs and returns the proof. Desktop then submits the statement to the People Chain node on the Product's behalf with the proof attached.
- **Account context**: The statement is signed by the user's per-Product account: a sub-account derived from the user's identity and scoped to the Product's `.dot` domain. The Product never has to know the account address up front. Desktop resolves the right account and uses it for the submission.
- **Per-Product topic scope**: The Product SDK tags every submission with `blake2b(appName)` as its primary topic; subscribers from other Products on the same network see only their own traffic. The scope is set up at the Host API boundary so a misconfigured Product cannot accidentally publish into another Product's topic.


What Desktop Does Not Do

## What Desktop Does Not Do

A few responsibilities sit with the Product, not with Desktop:

- **Product topic settings**: The Host attaches the per-Product primary topic, but secondary `topic2`, channels (last-write-wins state), and per-statement TTL come from the Product's call.
- **Delivery semantics**: Statement Store delivery is best-effort gossip. There is no retry, no acknowledgement, and no ordering guarantee at the network layer. If your Product needs an acknowledgement, the recipient publishes one back. Reliability is composed at the application layer; Desktop does not add a queue or retry pipeline behind the scenes.


Composition with the Bulletin Chain

## Composition with the Bulletin Chain

The Statement Store is the right layer for ephemeral signaling. When content needs to outlive the statement TTL, the canonical pattern is to store it on the Bulletin Chain and publish the resulting CID as the statement payload. This composition powers the App's [Chat](/reference/apps/hosts/polkadot-app/chat/) feature and many other Product patterns:

- **Statement Store** carries the live signal (presence, "new message arrived", typing indicators).
- **Bulletin Chain** stores the durable content readers fetch later by hash.

Both layers are reached through Desktop's Host API and the same per-Product account context applies across them.


Where to Go Next

## Where to Go Next

- Guide **Exchange Ephemeral Messages**

    ---

    The Product-side how-to: setting up the Statement Store client, subscribing, publishing typed statements, and using channels for last-write-wins state.

    [:octicons-arrow-right-24: Get Started](/apps/build/pub-sub-off-chain-data/)

- Guide **Store Data on Chain**

    ---

    The Bulletin Chain layer that composes with the Statement Store: write the durable content, publish the CID as a statement.

    [:octicons-arrow-right-24: Get Started](/apps/build/store-data-on-chain/)


Introduction

## Introduction

The Host API surface a Product calls on Polkadot Web is the same TrUAPI surface as on Polkadot Desktop. The same method groups, the same signatures, and the same SDK packages apply. Code written for Desktop runs on Web. This page documents the _exceptions_ to that statement, focusing on the small number of capabilities whose underlying behavior is materially different because the runtime is a browser, not an installed application.

For the full TrUAPI reference (method groups, versioning, package table), see [Protocol: TrUAPI](/reference/apps/protocol/truapi/).

!!! warning "Provisional"
    The per-method-group behavioral matrix between Polkadot Web and Polkadot Desktop is still being finalized. This page documents the categories where behavior is known to differ and the conceptual reason for each; the per-method specifics will be added once the surface is confirmed.


What Is the Same

## What Is the Same

By default, assume the following behavior is the same on Web as on Desktop:

- Chain interaction, storage reads, transaction building, and `signAndSubmit` work identically.
- Per-Product sub-accounts derive the same way and resolve to the same addresses.
- Permissions are declared the same way in the manifest and gate the same capabilities at the Host API boundary.
- Signing routes to the paired Polkadot App with the same per-transaction approval model.

A Product that targets Web can use the same `@parity/product-sdk` packages and the same TrUAPI method group calls; the SDK abstracts away the Host difference at every point where it matters.


Where Browser-Context Differs

## Where Browser-Context Differs

Three categories are where browser-context behavior diverges and a Product developer may need Web-specific handling:

- **Local storage backing**: The Product SDK's [`KvStore`](/apps/build/persist-data-locally/) routes through the Host on Web exactly as on Desktop, but the underlying backend the Host uses is different: browser-managed storage rather than the installed app's on-device storage. Capacity, eviction behavior, and clear-history semantics follow the browser's rules.
- **Outbound requests under the `ExternalRequest` permission**: Pattern-scoped outbound requests still work, but the request itself is dispatched from a browser context. CORS, cookies, and the browser's network policies all apply on top of the Host's pattern enforcement. A request the Host would allow may still be blocked by the browser if the target server's CORS policy rejects it.
- **Media capabilities**: Media-access permissions such as `Microphone` are gated by both the Host's permission system and the browser's media-permission prompt. The user has to grant both. Build UI that handles the two-prompt path gracefully.

A Product that uses none of those three categories needs no Web-specific code.


Where to Go Next

## Where to Go Next

- Guide **Persist Data Locally**

    ---

    The Product-side how-to for `KvStore`, including the cross-environment behavior the Web Host inherits.

    [:octicons-arrow-right-24: Get Started](/apps/build/persist-data-locally/)


Introduction

## Introduction

Polkadot Web is the browser-based Host that loads Polkadot Products from any browser tab — no install required. Served at `dot.li`, it is the third sibling alongside the [Polkadot App](/reference/apps/hosts/polkadot-app/) and [Polkadot Desktop](/reference/apps/hosts/polkadot-desktop/). Its job is the same as theirs: load a Polkadot Product inside a sandbox, mediate everything it touches (signing, chain access, storage, outbound requests) through the Host API.

What makes Web different from Desktop is not the _model_ — it is the _delivery_. Web runs in a regular browser instead of an installed application, which changes:

- **The trust surface**: The browser is the runtime.
- **The visiting flow**: A Product is loaded by navigating to it in a browser tab, not from an installed address bar.
- **The upgrade path**: Products and the Host itself update on page load, not via an OS installer.

The Product surface a developer targets, including `.dot` name addressing, the TrUAPI surface, and the per-Product sub-account model, is the same in either Host.

!!! warning "Provisional"
    Polkadot Web is being actively built and several of its developer-facing surfaces are not yet finalized. Pages in this subsection document the conceptual model and the parts that are stable; surface-level specifics carry per-page provisional callouts and will be filled in once confirmed.


Architecture

## Architecture

At a high level, three properties matter to a Product developer building for Web:

- **Browser-tab runtime**: Polkadot Web is a regular browser page at `dot.li`. Products are loaded inside it, not as standalone tabs.
- **Same sandbox contract as Desktop**: A Product running on Web sees the same per-Product account model, the same TrUAPI surface, and the same permission system as a Product running on Desktop. Code that works in Desktop will work on Web, with surface differences called out per-page in this subsection.
- **Pairs with the Polkadot App for signing**: Like Desktop, Polkadot Web does not hold the user's signing key. A browser session pairs with the user's paired App, and every signed action goes through the App for per-transaction approval.


Visiting and Shield States

## Visiting and Shield States

Two concepts are specific enough to Web to deserve their own pages:

- [Visiting a Product](/reference/apps/hosts/polkadot-web/visiting/): How a `.dot` name is resolved and a Product is loaded into a browser tab, and how this differs from Desktop's address-bar flow.
- [Shield States](/reference/apps/hosts/polkadot-web/shield-states/): The security-indicator UI that surfaces the trust posture of the loaded Product, including bundle verification and Host state.


Host API on Web

## Host API on Web

The TrUAPI surface a Product calls on Web is materially the same as on Desktop. There are a small number of capabilities where the underlying behavior differs because of the browser context (storage, outbound requests, media access), and those are documented at [Host API](/reference/apps/hosts/polkadot-web/host-api/).


On-Chain `polkadot.com`

## On-Chain `polkadot.com`

A Polkadot Product can also serve as the meta-surface that points to other Products: a discovery layer running as a Product itself. The canonical instance of this is [On-Chain polkadot.com](/reference/apps/hosts/polkadot-web/onchain-polkadot-com/), which is the on-chain-published presence backing the `polkadot.com` site.


Upload Journeys

## Upload Journeys

!!! warning "Provisional"
    The flows for publishing content from a Polkadot Web Host are still being defined, including uploading assets, registering a `.dot` Product, and updating a published bundle from within Web. They will be documented here once finalized.


Where to Go Next

## Where to Go Next

- Learn **Visiting a Product**

    ---

    How Polkadot Web resolves a `.dot` name and loads the resulting Product into a browser tab.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-web/visiting/)

- Learn **Shield States**

    ---

    The security-indicator UI on Web and what each shield state means for a Product the user is interacting with.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-web/shield-states/)

- Learn **Host API on Web**

    ---

    Where the Web Host's TrUAPI surface differs in behavior from Desktop because of the browser context.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-web/host-api/)


Introduction

## Introduction

On-chain `polkadot.com` is `polkadot.com` itself, served as a Polkadot Product. It is the discovery layer for the ecosystem, a directory that points at other Polkadot Products, but it is not hosted on a centralized server. It is published as a bundle, resolved through [DotNS](/reference/apps/infrastructure/dotns/), and loaded by Polkadot Web or Polkadot Desktop into the Host sandbox, the same way any other Product is.

This page explains what makes the on-chain `polkadot.com` Product different from any other Product, and where it fits in the larger publishing flow. Mechanically, it is not different, and that is the point.


Why an On-Chain Discovery Layer

## Why an On-Chain Discovery Layer

A Polkadot Product is addressed by its `.dot` name, but `.dot` names alone are flat. A user has to know the name before they can visit it. Discovery is the layer above that: showcases, categories, recommendations, search.

Putting discovery on-chain as a Polkadot Product itself has two properties an off-chain discovery site does not:

- **Verifiable provenance**: The directory's contents are addressable and verifiable; a user can confirm that the discovery layer they are looking at matches the on-chain CID that DotNS resolves to, and the same shield-state checks that apply to any other Product apply here.
- **Composability**: Other Products can read the same on-chain discovery state through the chain client surface (see [Read Chain State](/apps/build/read-chain-state/)), without needing a private API to a centralized directory.


Implications for a Product Developer

## Implications for a Product Developer

If you are building a Product, two things matter about on-chain `polkadot.com`:

- **Publishing target**: The flow for getting your Product listed on the canonical discovery surface goes through whatever submission and curation process on-chain `polkadot.com` defines. The Product-side how-to for the underlying publishing steps is [Register and Publish](/apps/deploy-your-app/).
- **Model to copy**: Any Product that wants to be a discovery surface for a specific category, such as a games directory, a wallet directory, or an asset explorer, can follow the same pattern: publish a Product whose state is the directory, read it from chain, and let the Host render it the same way.


Where to Go Next

## Where to Go Next

- Guide **Publish Your App Bundle**

    ---

    The Product-side how-to for bundling and publishing your Product, including the artifact-addressing steps that any directory-listed Product goes through.

    [:octicons-arrow-right-24: Get Started](/apps/deploy-your-app/)

- Guide **Read Chain State**

    ---

    The how-to for reading on-chain state from inside a Product, including reading state published by other Products like on-chain `polkadot.com`.

    [:octicons-arrow-right-24: Get Started](/apps/build/read-chain-state/)


Introduction

## Introduction

When a user opens a Polkadot Product on Polkadot Web, they're trusting a few things: that the bundle their browser fetched matches what [DotNS](/reference/apps/infrastructure/dotns/) says the `.dot` name points at, that the Host's state is what it should be, and that nothing in the runtime has been tampered with. Shield states are how Polkadot Web surfaces that trust posture in the browser UI — a security indicator the user can glance at to see whether the loaded Product is in a known-good state.

This page documents what shield states exist, what each one means, and when the state changes.

!!! warning "Provisional"
    The full list of shield states, the exact UI affordances Polkadot Web uses to surface them, and the triggers that cause a state transition are still being finalized. This page describes the conceptual model; the per-state reference (every name, color, icon, and verbatim explanation surfaced to the user) will be added once confirmed.


Conceptual Model

## Conceptual Model

A shield state communicates two things at once:

- **Bundle integrity**: Does the running bundle match the CID that DotNS resolves to for the `.dot` name in the address bar? A mismatch, such as a Product loaded from a stale cache that no longer matches the published version, is a state transition worth showing.
- **Host posture**: Is the Host's expected runtime state intact? Web's sandbox guarantees only hold if the Host itself is in a known state; the shield surfaces deviations.

A user will see a single shield indicator at any moment, and that indicator tells them whether everything is in the "expected" posture or whether something the user should know about has happened.


Why Products Should Care

## Why Products Should Care

For a Product developer, the shield states are not a surface your code calls directly. They are a property of the Host that affects how users perceive your Product. Two implications:

- **Host-owned indicator**: A Product cannot override or hide the shield state. The indicator lives in the Host's UI, outside the Product's sandbox. This is intentional: a Product cannot mask a security state from its users.
- **Reload signals**: Drastic shield-state changes can signal a reload. If a user is in the middle of a long-running interaction with your Product and DotNS points the `.dot` name at a different CID, the Host may transition to an "out-of-sync" state and prompt the user to reload. Build flows that tolerate this, such as idempotent retries and durable client-side state via [`KvStore`](/apps/build/persist-data-locally/), rather than assuming a single Product session is uninterrupted.


Where to Go Next

## Where to Go Next

- Learn **Visiting a Product**

    ---

    The visiting flow that establishes the initial shield state when a Product is loaded.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-web/visiting/)


Introduction

## Introduction

The defining flow of Polkadot Web is visiting a Polkadot Product by its `.dot` name from inside a regular browser tab. The mechanism is conceptually the same as Polkadot Desktop's address-bar resolution, but the delivery is different. There is no installed application, and the entry point is a URL.

This page is the reference for what happens between the user typing a `.dot` name and the Product running inside the Web Host.


The Visiting Flow

## The Visiting Flow

From the user's perspective:

1. The user navigates to `https://<name>.dot.li` (or otherwise enters a `.dot` name in the Web Host's UI).
2. Web resolves the `.dot` name through DotNS, retrieving the content reference (CID) for the published Product bundle.
3. Web fetches the bundle from the Bulletin Chain (or its delivery layer) by CID.
4. Web prepares the sandboxed container the Product will run inside and loads the bundle.
5. The Product is now running in the user's browser, with the Host API available for it to call.

If the user is not already signed in via their Polkadot App, the Host triggers the pairing handshake before any signed action becomes possible. Reading chain state, browsing the Product's UI, and interacting with anything that does not require signing all work before sign-in.


How This Differs from Polkadot Desktop

## How This Differs from Polkadot Desktop

The Product's experience is the same; the path to the Product is what differs:

- **No installer**: Desktop is a specialized browser the user installs; Web is a URL.
- **Browser-tab entry**: Web inherits the browser's history, back/forward, and tab model. A Product on Web behaves more like a navigated webpage than an opened application.
- **Updates on load**: Each visit fetches the published bundle. Web has no "update available" prompt. The user gets the version DotNS resolves to for that visit.

The trade-off is on the trust surface: Web depends on the user's browser as part of its runtime. The Host can verify the bundle it fetched matches the CID DotNS resolved to, but the user has to trust the browser to honor the sandbox. The [Shield States](/reference/apps/hosts/polkadot-web/shield-states/) reference documents how Web surfaces this trust posture in its UI.


Where to Go Next

## Where to Go Next

- Learn **Shield States**

    ---

    How Polkadot Web surfaces the trust posture of the loaded Product, including what each shield state means and when it changes.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-web/shield-states/)


Introduction

## Introduction

This is the technical-depth companion to the [App Development](/apps/) how-to guides. Where the guides walk you through tasks step by step, this section explains _what each component is, how it works, and where its limits are_ — the level of detail you need when integrating against the surface.

A Polkadot Product is a sandboxed application you build that runs inside one of the Polkadot Apps. The Host it runs in mediates everything sensitive, including signing, chain access, storage, and outbound requests, through a protocol called TrUAPI, and the Product talks to Polkadot's on-chain infrastructure through the SDK and the Host. This reference is organized along those axes: Hosts, the TrUAPI protocol between Host and Product, and the infrastructure components Products consume.

!!! info "Depth target"
    Each page in this section follows the same shape: a short conceptual frame up top, then the developer-facing surface (Host API method tables for Hosts, pallet surface tables for infrastructure) at the bottom. The [TrUAPI](/reference/apps/protocol/truapi/) subsection, with one page per method group, is the depth model for protocol reference pages.


Architecture

## Architecture

Your Product sits at the top of a layered stack. You write the Product itself; everything below — the [Product SDK](/reference/glossary/#polkadot-sdk) that exposes typed methods, the Polkadot Apps that load and sandbox your Product, and the underlying chains, decentralized storage, and name service — is provided by the platform. The [Host](/reference/glossary/#host) (whichever Polkadot App is loading your Product) mediates every interaction through [TrUAPI](/reference/apps/protocol/truapi/) and prompts the user for anything sensitive.

![Polkadot Apps architecture: your Polkadot Product uses the Product SDK to talk to a Polkadot App (App, Desktop, or Web), which accesses Polkadot infrastructure](/images/reference/apps/index/polkadot-environment.svg)


Hosts

## Hosts

Hosts are the runtime containers that load and run Polkadot Products:

- **[Polkadot App](/reference/apps/hosts/polkadot-app/)**: The mobile Host. Holds the user's signing key, runs Proof of Personhood, and is the canonical signer for every transaction a Product submits anywhere in the Triangle.
- **[Polkadot Desktop](/reference/apps/hosts/polkadot-desktop/)**: The desktop Host. Loads Products by `.dot` name, mediates signing requests to the paired mobile App, and exposes the Host API surface to the Product running inside it.
- **[Polkadot Web](/reference/apps/hosts/polkadot-web/)**: The web Host (`dot.li`). Loads Products in a browser sandbox and documents the visiting flow, shield states, and on-chain `polkadot.com` integration.


Protocol

## Protocol

The [TrUAPI](/reference/apps/protocol/truapi/) reference documents the protocol between Hosts and Products: the conceptual sandbox model, the 11 method groups (TrUAPI Calls, Permissions, Local Storage, Account Management, Signing, Chat, Statement Store, Preimage, Chain Interaction, Payment, Entropy), the versioning model, and the package reference table.


Infrastructure

## Infrastructure

Per-component reference for the on-chain infrastructure Products consume:

- **[Bulletin Chain](/reference/apps/infrastructure/bulletin-chain/)**: Content-addressed storage with explicit authorization, chunked uploads, time-bound retention, and renewal.
- **[Statement Store](/reference/apps/infrastructure/statement-store/)**: Gossip-distributed, signed statements on the People Chain for real-time signaling between users.
- **[dotNS](/reference/apps/infrastructure/dotns/)**: The `.dot` name system, including PopRules pricing, the contract architecture, and the registration flow.
- **[Proof of Personhood](/reference/apps/infrastructure/pop/)**: The Ring-VRF mechanism and the per-pallet surface (people, game, score, identity, universal basic capacity, coinage).
- **[HOP](/reference/apps/infrastructure/hop/)**: The cross-chain hop protocol.


Skills

## Skills

The [product-sdk](/reference/apps/skills/) skills reference documents what skills exist, what each one does, and how to use them inside your Product workflow.


Where to Go Next

## Where to Go Next

- Learn **Hosts**

    ---

    Start with the Polkadot App, the mobile Host that holds the signing key and runs Proof of Personhood for every Product in the Triangle.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-app/)

- Guide **App Development How-To**

    ---

    If you are new here, start with the how-to guides: set up Polkadot Desktop, then build your first Product against the SDK surface this reference documents.

    [:octicons-arrow-right-24: Get Started](/apps/get-started/)


Introduction

## Introduction

The Bulletin Chain has no token balance for storage. You cannot "pay for storage" the way you pay a transaction fee on a typical chain. Instead, every account that wants to write to Bulletin needs an explicit authorization: an on-chain record that grants a quota of transactions and bytes, with an expiration block.

A write attempted without authorization is rejected at the boundary. This page is the reference for how authorizations are shaped, how they are checked, and what happens when they expire.


What an Authorization Records

## What an Authorization Records

An authorization is a per-account on-chain record stored in the `Authorizations` storage map of the `transaction-storage` pallet. It records, for the account it covers:

- **Remaining transactions**: How many storage extrinsics the account may still submit before the quota is exhausted.
- **Remaining bytes**: How many bytes total the account may still write across those transactions.
- **Expiration block**: The block at which the authorization expires. Unused capacity is _not_ refunded when this block passes.

A Product can verify an account's current authorization by reading the `Authorizations` storage map for that account through the standard chain client.


What a Write Costs

## What a Write Costs

Each storage submission decrements both counters:

- The transaction counter decrements by one per extrinsic.
- The byte counter decrements by the payload size.

The transaction counter is the one most Products will hit first. Even a small upload that uses chunking (because the payload exceeds the per-transaction byte limit) consumes one transaction per chunk; large files consume the corresponding count.


Expiration

## Expiration

Authorizations are time-bounded for a reason: storage on the network is finite, and an unexpiring authorization would let an inactive account hold reserved capacity indefinitely. When the expiration block passes:

- Any remaining transaction and byte quota in that authorization is _forfeited_ (not credited to a new authorization, not refunded to the user).
- Subsequent storage attempts return an authorization error until a new authorization is provisioned.

A Product whose users store data over time needs to think about authorization renewal as a first-class concern, not a once-at-onboarding step.


Provisioning on TestNet

## Provisioning on TestNet

!!! warning "Provisional"
    The TestNet provisioning flow — the faucet endpoint, the request UX, governance- or sudo-routed grants where they apply — is being firmed up. The current flow lives in the [Get TestNet Tokens](/apps/get-started/get-testnet-tokens/) guide; that guide is the source of truth as the surface stabilizes.

On TestNet today, authorizations are provisioned through a faucet built into the Bulletin Chain Console. The [Get TestNet Tokens](/apps/get-started/get-testnet-tokens/) guide walks through requesting an authorization for a paired account.


Where to Go Next

## Where to Go Next

- Learn **Renewal**

    ---

    What happens when an authorization or a stored item approaches expiration, and the mechanics of keeping data alive.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/renewal/)

- Guide **Get TestNet Funds**

    ---

    The setup step that provisions an authorization on TestNet alongside PAS tokens for transaction fees.

    [:octicons-arrow-right-24: Get Started](/apps/get-started/get-testnet-tokens/)


Introduction

## Introduction

Every Bulletin Chain storage extrinsic carries a hard per-transaction byte limit. A payload smaller than the limit goes in a single transaction. A payload larger than the limit is chunked: the SDK splits the bytes into chunks, uploads each chunk in its own transaction, and writes a small DAG-PB manifest describing how the chunks reassemble. The CID returned for a chunked upload is the CID of the manifest, not of any individual chunk; readers fetching that CID get the manifest, follow it to the chunk CIDs, and reassemble the original payload.

For most Products, this is transparent — `app.bulletin.upload(bytes)` accepts a payload of any size up to the SDK's supported maximum, and the chunking pipeline runs underneath. This page documents what the pipeline does and what trade-offs it surfaces.


What Happens Internally

## What Happens Internally

The SDK's chunking pipeline runs roughly this sequence:

1. Split the payload into fixed-size chunks (the chunk size is the SDK default, sized to fit comfortably under the per-transaction byte limit).
2. Upload each chunk in its own extrinsic, accumulating CIDs as the chain returns them.
3. Build a DAG-PB manifest a small object that lists the chunk CIDs in order, encoded in the DAG-PB format that IPFS-style readers recognize.
4. Upload the manifest itself as a final small transaction.
5. Return the manifest CID to the Product.

Readers retrieving the manifest CID get back the manifest first, then issue parallel fetches for each chunk CID and reassemble. Because both the chunks and the manifest are content-addressed, readers can verify each piece independently.


What This Costs

## What This Costs

Chunked uploads cost more than single-transaction uploads because each chunk consumes one transaction from the [authorization](/reference/apps/infrastructure/bulletin-chain/authorization/) quota. A Product uploading large payloads on behalf of many users should budget transaction quota accordingly — running out of transactions even with plenty of bytes remaining is a realistic failure mode.

The manifest itself counts as one additional transaction on top of the chunk count.

!!! warning "Provisional"
    The exact chunk size used by the SDK, the maximum supported payload size, the per-transaction byte limit on the current chain build, and any tunables exposed for advanced flows are still being finalized. The conceptual pipeline above is stable; per-value specifics will be added once confirmed.


What a Product Sees

## What a Product Sees

A Product calling `app.bulletin.upload(bytes)` sees the same shape regardless of whether chunking ran underneath:

- The call returns a CID.
- The call decremented the account's authorization quota by the appropriate amount (1 + chunk count for a chunked upload, 1 for a single-transaction upload).
- A subsequent `app.bulletin.fetch(cid)` retrieves the original payload.

The chunking is an implementation detail of the upload pipeline, not part of the surface a Product needs to manage. For Products that want explicit control (custom chunk size, parallelism limits, progress reporting on large uploads), the [Store Data on Chain](/apps/build/store-data-on-chain/) guide covers the lower-level `BulletinClient` and the chunk-level controls it exposes.


Where to Go Next

## Where to Go Next

- Learn **Authorization**

    ---

    The quota model that chunked uploads consume — why transaction count, not only byte count, matters when uploading large files.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/authorization/)

- Guide **Store Data on Chain**

    ---

    The Product-side how-to: small writes, larger files with chunking, and the lower-level `BulletinClient` surface for advanced control.

    [:octicons-arrow-right-24: Get Started](/apps/build/store-data-on-chain/)


Cross-Chain Bulletin Storage via People Chain

Introduction

## Introduction

A Polkadot Product's identity, accounts, and PoP state all live on the People Chain. Storage capabilities live on the Bulletin Chain. When a Product needs to store something that should be attached to the user's identity — proof material tied to PoP, content the People Chain itself references, anything the People Chain side of a flow needs to commit to before the Bulletin Chain side completes — the natural origin for the storage call is the People Chain, not Bulletin directly.

The cross-chain path makes this work: a storage call dispatched on the People Chain crosses to the Bulletin Chain via XCM (Cross-Consensus Messaging) and lands the storage record there, with the People Chain identity carried through as the originating context.


The Flow

## The Flow

!!! warning "Provisional"
    The exact XCM payload, the receiving pallet on Bulletin, and the response routing for cross-chain storage operations are still being finalized. This page documents the conceptual flow; the protocol-level message format and per-step diagram will be added once they are confirmed.

Conceptually, a cross-chain Bulletin write goes through these steps:

1. The Product dispatches a storage call on the People Chain rather than directly on Bulletin. The call carries the payload (or CID, for large payloads pre-uploaded) and any People-Chain-side context the Bulletin record should be associated with.
2. The People Chain wraps the call in an XCM message addressed to the Bulletin Chain. The message carries the originating account context so the Bulletin side can attribute the storage to the right authorization.
3. The Bulletin Chain receives the XCM message and enacts the storage extrinsic on behalf of the originating account, subject to that account's Bulletin authorization quota.
4. The result returns to the People Chain side of the flow, where the Product can observe the outcome through the standard PAPI subscription on the People Chain.

The CID the Bulletin Chain returns is the same CID a direct write would have produced — content addressing is content addressing, regardless of origin.


When to Use the Cross-Chain Path

## When to Use the Cross-Chain Path

Most Products will not need this path. For a typical "store a profile photo, get a CID, embed in a `.dot` site" flow, writing directly to the Bulletin Chain is simpler. The cross-chain path becomes useful when:

- The storage is tied to a People Chain operation — for example, a governance proposal whose body is referenced from the People Chain side of a flow.
- The storage must be authorized against the People Chain identity in a way that a direct Bulletin write cannot easily attribute.
- The Product is already orchestrating a multi-chain operation and adding a Bulletin write to that operation keeps the flow on a single dispatch path.

For everyday Bulletin writes, see [Store Data on Chain](/apps/build/store-data-on-chain/).


Where to Go Next

## Where to Go Next

- Learn **Authorization**

    ---

    Cross-chain writes still consume the originating account's Bulletin authorization quota — the same model as direct writes.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/authorization/)

- Guide **Store Data on Chain**

    ---

    The Product-side how-to for direct Bulletin writes, which is the right path for most use cases.

    [:octicons-arrow-right-24: Get Started](/apps/build/store-data-on-chain/)


Introduction

## Introduction

The Bulletin Chain is Polkadot's decentralized cloud storage layer for Products. Your Product's files and content live there, addressed by their hash so anyone can verify what they fetched. A Product writes data; the chain returns a [Content Identifier (CID)](/reference/glossary/#content-identifier-cid), which is a Blake2b-256 hash of the bytes, and anyone with that CID can fetch the data back peer-to-peer from the network.

If you have used IPFS, the mental model is the same: content addressed by hash, retrieved without a central host. The difference is that storage records and authorizations live natively on Polkadot.

Four properties define how a Product interacts with Bulletin:

- **Content-addressed by design**: The CID is the hash of the bytes; two users uploading identical bytes produce the same CID. Readers verify they got the bytes they expected without trusting the host that served them.
- **Permissionless reads**: Anyone with the CID can fetch from the network — no URL signing, no read auth, no CDN to configure. Privacy through encryption is the Product's responsibility (encrypt before storing if the payload is sensitive).
- **Explicit authorization for writes**: Bulletin Chain has no token balance for storage. Every account needs an [authorization](/reference/apps/infrastructure/bulletin-chain/authorization/) — a quota of transactions and bytes — before it can store anything.
- **Time-bound retention with renewal**: Data is retained for a default window (about two weeks); [renewal](/reference/apps/infrastructure/bulletin-chain/renewal/) keeps it alive past expiration; without renewal it falls off.


Architecture

## Architecture

!!! warning "Provisional"
    The full architecture diagram — the relationship between the on-chain storage records, the collator network that serves CIDs to readers, and the cross-chain delivery path from People Chain — is still being finalized. Per-layer specifics will be added once they are confirmed.

At a high level, two layers cooperate:

- The on-chain Bulletin Chain holds the _records_ — the CIDs, who is authorized to store, when each item expires. This is where writes are gated and where the authorization model is enforced. See [Authorization](/reference/apps/infrastructure/bulletin-chain/authorization/).
- The collator-served content network holds the _bytes_. Readers fetch by CID over the peer-to-peer layer; the chain holds the commitment that the bytes existed and the CID was valid at write time, the collator network actually delivers them.

This split is what makes Bulletin practical at content sizes that would not fit on a typical blockchain's storage: the chain's job is to bound _what counts as authorized storage_, not to physically hold every byte.


When to Use Bulletin

## When to Use Bulletin

Bulletin is the right layer for content that needs to outlive a session and be fetched later by hash. Profile photos, published articles, app bundles, encrypted message content for chat — anything where the readers are not all present at the same moment and the bytes have to be there later, by hash.

For the storage-layer comparison (Bulletin vs Statement Store vs local `KvStore`) see [Storage options for your Product](/apps/build/store-data-on-chain/), and for the Product-side how-to use [Store Data on Chain](/apps/build/store-data-on-chain/).


Where to Go Next

## Where to Go Next

- Learn **Authorization**

    ---

    The model that gates writes: no token balance, an explicit per-account authorization with a transaction-and-byte quota and an expiration block.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/authorization/)

- Learn **Chunked Uploads**

    ---

    How a payload larger than the per-transaction limit is uploaded as chunks under a DAG-PB manifest, transparently to the Product.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/chunked-upload/)

- Learn **Renewal**

    ---

    The retention lifecycle and the mechanics of renewing data before it falls off the network.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/renewal/)

- Learn **Cross-Chain**

    ---

    How a write initiated from the People Chain (where a Product's PoP identity lives) reaches the Bulletin Chain via XCM.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/cross-chain/)

- Guide **Store Data on Chain**

    ---

    The Product-side how-to: setting up the storage client, the Hello World write, retrieval, larger files, renewal.

    [:octicons-arrow-right-24: Get Started](/apps/build/store-data-on-chain/)


Introduction

## Introduction

Data on the Bulletin Chain has a bounded retention window. The chain doesn't promise to keep bytes forever; it promises to keep them for a default period (about two weeks), after which the storage record expires and the bytes can be evicted from the collator network unless the record is renewed.

This page documents the renewal lifecycle: what counts as "alive," what happens at expiration, what a Product has to do to keep data alive, and what costs renewal incurs.


The Default Retention Window

## The Default Retention Window

When a Product writes to Bulletin, the resulting storage record carries an expiration block — by default, approximately two weeks of blocks from the write. Between the write and the expiration block:

- **The data is _alive_**: Any reader with the CID can fetch the bytes from the collator network.
- **The chain enforces availability**: The on-chain record exists, and collators serving the network are expected to hold the bytes.

After the expiration block:

- The on-chain record is no longer "active." Fetches against the CID may continue to succeed for a window depending on collator caching, but the chain no longer guarantees the bytes are reachable.
- Eventually, collators evict the bytes. The CID still exists as a content reference, but the network can no longer serve it.


What Renewal Does

## What Renewal Does

A _renewal_ is a separate transaction (signed and submitted like any other) that extends the expiration block of an existing storage record. The data itself doesn't move — what changes is the record's expiration. After renewal:

- The on-chain record's expiration is pushed forward by another default window.
- Collators continue to hold and serve the bytes.

Renewal does not change the CID — readers continue to use the same hash they had before. A Product that has published a CID externally (in another statement, embedded in a `.dot` site, referenced by another pallet) does not have to update those references when it renews.


What Renewal Costs

## What Renewal Costs

Renewal consumes a transaction from the renewing account's [authorization](/reference/apps/infrastructure/bulletin-chain/authorization/) quota — same as the original upload would. Bytes are _not_ counted again (you are not re-uploading content), so the byte counter doesn't decrement, but each renewal call consumes one transaction.

For long-lived content (a profile photo, a published article, an app bundle), a Product should:

- Budget for periodic renewals as part of the account's quota planning.
- Schedule renewals before the expiration block, not at it — submission, inclusion, and finalization take time, and an authorization that itself expires on the same block prevents the renewal from going through.


What Happens to Forgotten Data

## What Happens to Forgotten Data

If a Product (or its operator) forgets to renew, the data eventually becomes unreachable. There is no manual recovery: once collators have evicted the bytes, only re-uploading the same payload from outside the chain restores availability. The CID will be the same (because the bytes are the same), but a new upload is a fresh transaction against a fresh authorization slot.

!!! warning "Provisional"
    The exact default retention window, the renewal grace period (if any) between expiration and eviction, and any batch-renewal primitives for renewing many CIDs in a single transaction are still being finalized. The conceptual lifecycle above is stable.


Where to Go Next

## Where to Go Next

- Learn **Authorization**

    ---

    The quota model that renewals consume — why a renewal needs a live authorization the same way a fresh upload does.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/bulletin-chain/authorization/)

- Guide **Store Data on Chain**

    ---

    The Product-side how-to that covers the renewal call alongside the basic store and retrieve flow.

    [:octicons-arrow-right-24: Get Started](/apps/build/store-data-on-chain/)


Introduction

## Introduction

dotNS is implemented as a set of cooperating contracts on Asset Hub, not as a single monolithic registrar. The split exists because the responsibilities are genuinely different — managing name records, enforcing PopRules pricing, and handling transfers are separate jobs — and contract boundaries map cleanly onto those slices.

This page documents what each contract is responsible for at a conceptual level, so a Product developer building against the dotNS surface knows which contract handles which interaction.

!!! warning "Provisional"
    The complete contract map (every contract's name, address, ABI, and the precise responsibilities split between them) is still being finalized. This page documents the conceptual responsibilities; the per-contract reference will be added once the deployment is confirmed. The [TestNet Contracts](/reference/apps/infrastructure/dotns/testnet-contracts/) page tracks the current addresses as they stabilize.


Conceptual Responsibilities

## Conceptual Responsibilities

The contract set covers nine slices of the registry's job, grouped into three families:

- **Registry core**: The contracts that hold the name records themselves:

    - A registry contract holding the `(namehash → record)` mapping and gating who can write to each record.
    - A resolver contract responding to queries — read-side surface for "what record does this `namehash` currently have?"
    - A records contract or substructure storing the `contenthash`, owner, and other per-name fields a resolver returns.

- **Registration and pricing**: The contracts that gate who can register what:

    - A PopRules contract that evaluates a proposed registration against the pricing ladder (name length × PoP tier × suffix → free or deposit).
    - A registrar contract that orchestrates the full registration flow: PopRules check, fee collection if applicable, write to the registry.
    - A deposit/treasury contract managing the deposits paid by open-tier registrations.

- **Lifecycle**: The contracts that handle changes after registration:

    - A transfer contract handling owner-changes for an existing name. See [Name Transfers](/reference/apps/infrastructure/dotns/transfer/).
    - A renewal contract (or sub-mechanism) handling annual or per-period renewals where applicable.
    - An admin/governance contract for operations that need to be governance-routed (reserved-name allocations, dispute resolution, contract upgrades).

A Product developer rarely interacts with the contracts directly — the [CLI](/reference/apps/infrastructure/dotns/cli/) and the higher-level [Register and Publish](/apps/deploy-your-app/) flow wrap the registration interactions. A Product reading name resolution data does so through the standard chain-client surface, calling into the resolver contract via the typed PAPI descriptor for Asset Hub.


Where to Go Next

## Where to Go Next

- Learn **PopRules and Pricing**

    ---

    The ladder the registrar contract evaluates against — name length, PoP tier, deposit amounts.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/poprules-pricing/)

- Learn **TestNet Contracts**

    ---

    The current TestNet addresses for the dotNS contract set, tracked as the surface stabilizes.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/testnet-contracts/)


Introduction

## Introduction

[`@parity/dotns-cli`](https://www.npmjs.com/package/@parity/dotns-cli) is the command-line tool for interacting with the dotNS registry — registering a `.dot` name, updating its `contenthash`, transferring ownership, and renewing where applicable. It is the canonical way to perform these operations outside of the higher-level [Register and Publish](/apps/deploy-your-app/) flow that the Polkadot Product setup track wraps.

A Product developer building a typical publishing pipeline rarely calls the CLI directly — the setup track handles the common path. The CLI is the right tool when you need a fine-grained, scriptable interaction (CI publishing, batch operations across multiple names, debugging a registration failure).

!!! info "CLI version"
    This page targets `@parity/dotns-cli` `0.6.2`. The CLI is in active development and breaking changes between versions are expected. To follow this reference, install this version (or check the page's last update against the latest release on npm).


Command Families

## Command Families

The CLI exposes commands across three families that map onto the dotNS contract responsibilities:

- **Registration**: Commands that create a name record:

    - Register a new name with a starting `contenthash`.
    - Check PopRules eligibility for a proposed name and account (preview the deposit / free-tier outcome before submitting).

- **Records management**: Commands that mutate an existing name's fields:

    - Update the `contenthash` to a new CID — this is what a Product owner runs when they publish a new bundle and want the `.dot` name to point at the new version.
    - Set or unset administrative fields on the record.

- **Lifecycle**: Commands that change ownership or extend the registration:

    - Transfer the name to another account.
    - Renew the registration where renewals apply.


Installing and Authenticating

## Installing and Authenticating

The CLI is distributed as an npm package. Install it globally or run via `npx`. Operations that mutate state (registration, update, transfer) require an account that can sign the resulting Asset Hub transaction — the CLI accepts a key file, a connected hardware signer, or a Polkadot App session via a pairing flow, depending on the operation and the security posture the operator chooses.

For day-to-day Product publishing, the recommended account is the same paired account a developer uses with Polkadot Desktop, so PopRules tier and any reserved-name claims continue to apply consistently across the CLI and Desktop paths.


Command Surface

## Command Surface

Each command — subcommand path, required flags, optional flags, and exit codes — is enumerated here.

!!! warning "Provisional"
    Per-flag details for each command are still being audited against the published surface. The table below lists the known top-level commands at `0.6.2`; the per-flag reference will be filled in once it is confirmed against the live package.

| Command                                  | Family            | Required flags | Optional flags | Notes      |
|:-----------------------------------------|:------------------|:---------------|:---------------|:-----------|
| `register domain`                        | Registration      | _Pending_      | _Pending_      | _Pending_  |
| `register subname`                       | Registration      | _Pending_      | _Pending_      | _Pending_  |
| `lookup`                                 | Records           | _Pending_      | _Pending_      | _Pending_  |
| `content view` / `content set`           | Records           | _Pending_      | _Pending_      | _Pending_  |
| `text view` / `text set`                 | Records           | _Pending_      | _Pending_      | _Pending_  |
| `pop set` / `pop info`                   | Records           | _Pending_      | _Pending_      | _Pending_  |
| `store`                                  | Records           | _Pending_      | _Pending_      | _Pending_  |
| `account`                                | Lifecycle         | _Pending_      | _Pending_      | _Pending_  |
| `bulletin`                               | Lifecycle         | _Pending_      | _Pending_      | _Pending_  |


Where to Go Next

## Where to Go Next

- Guide **Register and Publish**

    ---

    The higher-level publishing flow that wraps the most common CLI operations.

    [:octicons-arrow-right-24: Get Started](/apps/deploy-your-app/)

- Learn **TestNet Contracts**

    ---

    The current TestNet contract addresses the CLI targets when operating in TestNet mode.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/testnet-contracts/)


Introduction

## Introduction

dotNS is Polkadot's decentralized name service for Products — the registry that turns a human-readable `.dot` name like `awesome.dot` into the published Polkadot Product it points at. It's the lookup every Host runs whenever a user navigates to a `.dot` address.

If you have used a DNS provider, the role is similar: human-readable names map to content. The differences: dotNS is on-chain (no DNS provider in the middle), name resolution returns a [Content Identifier (CID)](/reference/glossary/#content-identifier-cid) for a Product bundle (not an IP address), and pricing is tied to [Proof of Personhood](/reference/apps/infrastructure/pop/) so spam farming short names is bounded.

Four properties shape how a Product developer interacts with dotNS:

- **The registry lives on Asset Hub**: Names, owners, and the content references they point at are stored as contract state on Asset Hub, not on the People Chain or Bulletin Chain.
- **Name resolution is content-addressed at the end**: A `.dot` name resolves to a CID, and the CID points at bytes on the [Bulletin Chain](/reference/apps/infrastructure/bulletin-chain/) (or via an IPFS gateway). See [Name Mechanism](/reference/apps/infrastructure/dotns/name-mechanism/).
- **Pricing is personhood-gated by PopRules**: Short names are free for personhood holders; longer or numerically-suffixed names are open to anyone but require a deposit. See [PopRules and Pricing](/reference/apps/infrastructure/dotns/poprules-pricing/).
- **The architecture is a small set of cooperating contracts**: Not a single registrar — a set of contracts each handling a slice of the model. See [Architecture](/reference/apps/infrastructure/dotns/architecture/).

For the Product-side how-to (registering a name, publishing your bundle), see [Register and Publish](/apps/deploy-your-app/).

!!! warning "Known gaps"
    Two operational caveats apply to the current dotNS surface:

    - **Self-declared PoP tier**: dotNS reads PoP tier from a status the user sets themselves. On-chain verification of PoP tier against the People Chain is a forthcoming integration; until then, treat the tier check as cooperative, not adversarial.
    - **Operational runbook gaps**: Some operator-side procedures (migration, batch updates, contract upgrade paths) are not yet documented for this build. The reference here covers the developer-facing surface.


Where to Go Next

## Where to Go Next

- Learn **Name Mechanism**

    ---

    How a `.dot` name resolves to a Product bundle — `namehash` derivation, the `contenthash` → CID mapping, and the IPFS/Bulletin delivery path.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/name-mechanism/)

- Learn **Architecture**

    ---

    The contract architecture on Asset Hub that backs the registry — what each contract is responsible for and how they cooperate.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/architecture/)

- Learn **PopRules and Pricing**

    ---

    The pricing ladder for name registration: who can register what at what cost, organized by name length and PoP tier.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/poprules-pricing/)

- Guide **Register and Publish**

    ---

    The Product-side how-to: registering a `.dot` name, attaching your published Product bundle, and going live.

    [:octicons-arrow-right-24: Get Started](/apps/deploy-your-app/)


Introduction

## Introduction

A `.dot` name is the front door a user enters to reach a Polkadot Product. Behind that front door, four layers cooperate to turn the name a user typed into the bytes a Host loads into its sandbox:

1. The dotNS registry on Asset Hub.
2. A `namehash` derivation that turns the string name into a deterministic key.
3. A `contenthash` record that points the `namehash` at a content reference.
4. A delivery layer (IPFS gateway, or Bulletin Chain peer-to-peer) that turns the content reference into bytes.

This page documents each of those layers so a Product developer knows what each one is doing and where to look when something doesn't resolve correctly.


Layer 1: The Registry on Asset Hub

## Layer 1: The Registry on Asset Hub

The registry of names — who owns `myproduct.dot`, when the registration was last updated, what record is currently attached — lives in contract state on Asset Hub, not on the People Chain or Bulletin Chain. Asset Hub is the natural home: it is Polkadot's system chain for asset and registry primitives, and dotNS is implemented as a set of contracts on it (see [Architecture](/reference/apps/infrastructure/dotns/architecture/)).

A registration creates a record; a transfer or update modifies it. A resolver reading the registry asks Asset Hub for the current state of a specific name and gets back the records associated with it, including the `contenthash` that points at the Product bundle.


Layer 2: Namehash Derivation

## Layer 2: Namehash Derivation

`.dot` uses an ENS-compatible `namehash` scheme to derive a deterministic key from the dotted name. For example, the name `myproduct.dot` is hashed in a recursive way (hash of `dot`, then hash of `(parent_hash, label_hash)`, where `label_hash` is the keccak hash of the label `myproduct`). The result is a fixed-size hash that the registry uses internally as the lookup key.

This is the same scheme ENS uses for `.eth`, which is intentional — the derivation is well-understood, well-tooled, and lets dotNS interoperate with the existing `namehash` ecosystem.


Layer 3: `contenthash` → CID

## Layer 3: `contenthash` → CID

Each name's record carries a `contenthash` field that points at the Product bundle. The format follows the ENS `contenthash` codec, which can encode:

- **An IPFS CID (with the appropriate codec prefix)**: The canonical pointer for content-addressed bundles.
- **A Bulletin Chain CID**: Polkadot-native content references, used the same way.

The `contenthash` is what changes when a Product publishes a new version: the name stays the same, the `contenthash` updates to point at the new CID. Old `contenthash` references can be retained for rollback or audit, depending on how the operator manages the registration.


## Layer 4: Delivery (IPFS Gateway or Bulletin Peer-to-Peer)

Once a resolver has the CID, the bytes still need to actually be fetched and handed to the Host. Two delivery paths:

- **IPFS gateway**: The CID is a standard IPFS reference; any IPFS gateway can serve it. Hosts can use a gateway integration for the fetch.
- **Bulletin Chain peer-to-peer**: For Bulletin CIDs, the chain's collator network serves the bytes peer-to-peer without going through a centralized gateway. This is the Polkadot-native path.

Both paths produce the same bytes, because both are addressing the same content by the same hash. A Host can fall back from one to the other if one path fails, or prefer one for policy reasons (e.g. always Bulletin peer-to-peer when available, to avoid a third-party gateway).


End-to-End Resolution

## End-to-End Resolution

Stitching the four layers together, a typical resolution looks like this:

1. A user navigates to `myproduct.dot` in a Host (Polkadot Web at `dot.li`, or Polkadot Desktop's address bar).
2. The Host computes the `namehash` of `myproduct.dot`.
3. The Host reads the contract record for that `namehash` from Asset Hub and extracts the `contenthash`.
4. The Host decodes the `contenthash` into a CID.
5. The Host fetches the bytes for the CID via the configured delivery path.
6. The Host validates the bytes against the CID (content-addressed verification) and loads them into the sandbox.

A failure at any layer surfaces as a specific shield-state transition in the Host UI (see [Shield States](/reference/apps/hosts/polkadot-web/shield-states/)) — for example, a stale-cache CID that no longer matches the current `contenthash` will show as an out-of-sync state.


Where to Go Next

## Where to Go Next

- Learn **Architecture**

    ---

    The contract architecture on Asset Hub that backs the registry layer above.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/architecture/)

- Learn **PopRules and Pricing**

    ---

    Who can register what name, and at what cost, before the resolution flow above ever runs.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/poprules-pricing/)

- Guide **Register and Publish**

    ---

    The Product-side how-to for creating a name record and attaching a `contenthash`.

    [:octicons-arrow-right-24: Get Started](/apps/deploy-your-app/)


Introduction

## Introduction

dotNS uses a scarcity ladder for `.dot` name registration. The shortest, most-premium names are reserved for governance or free to personhood holders; longer names are open to anyone for a deposit. The mechanism that enforces "free for personhood holders" is `PopRules` — the contract that evaluates a proposed registration against the registering account's PoP status and the requested name's length and suffix shape.

This page documents the ladder, the two PoP tiers `PopRules` recognizes, and the deposit formulas for open-tier registrations.


The Two PoP Tiers

## The Two PoP Tiers

`PopRules` recognizes two personhood tiers, registered separately on the People Chain:

- **PoP Full**: Cryptographically proven personhood, the destination state. The user completes the full biometric verification flow in the Polkadot App; their key joins the active membership ring on the People Chain. PoP Full holders can generate zero-knowledge proofs of personhood. See the [Proof of Personhood reference](/reference/apps/hosts/polkadot-app/pop/) for details.
- **PoP Lite**: Third-party attestation. An authorized attester submits an on-chain attestation that an account belongs to a real user; the account is registered against a separate `lite-people` ring. Lite supply is bounded by governance — it is the on-ramp; Full is the destination.

Both tiers qualify for free name registration, but at different name-length tiers.

!!! note "Self-declared PoP tier"
    dotNS reads PoP tier from a status the user sets themselves. On-chain verification against the People Chain is a forthcoming integration; until that ships, treat the tier check as cooperative, not adversarial.


The Pricing Ladder

## The Pricing Ladder

| Name format                                     | Who can register         | Deposit                                 |
|:------------------------------------------------|:-------------------------|:----------------------------------------|
| ≤5 chars                                        | Governance only          | —                                       |
| 6–8 chars (no numeric suffix)                   | PoP Full holders         | Free                                    |
| 6–8 chars + 2-digit suffix (e.g. `alice01`)     | PoP Lite or Full holders | Free                                    |
| 9–14 chars (no numeric suffix)                  | PoP Full holders         | Free                                    |
| 9–14 chars + 2-digit suffix (e.g. `acmecorp01`) | Anyone                   | `startingPrice × (15 − nameLength)` DOT |
| 15+ chars                                       | Anyone                   | `startingPrice / 2` DOT                 |

Two patterns explain the ladder:

- **Premium = short and unmarked**: A 6–8-character name with no numeric suffix is the most valuable shape; `PopRules` reserves it for PoP Full. A 6–8-character name with a 2-digit suffix is the next tier down; both PoP tiers can register one. Beyond that, the ladder opens up.
- **Anyone can buy length**: A 9–14-character name with a numeric suffix is open to anyone for a sliding-scale deposit; the longer the name, the smaller the deposit. A 15+-character name uses a fixed half-`startingPrice` deposit.


Lite → Full Migration Reservation

## Lite → Full Migration Reservation

When a PoP Lite holder registers a Lite-tier name (6–8 chars with suffix, or longer), dotNS reserves the matching no-suffix base name for them for 12 weeks. If the Lite holder upgrades to PoP Full within that window, they can claim the base name without contention — without the reservation, by the time they upgraded, someone else might have grabbed the unsuffixed name and they would have lost their identity continuity.

The reservation is automatic. A PoP Lite holder registering `alice01.dot` reserves `alice.dot` for themselves for 12 weeks; if they upgrade to Full in that window, `alice.dot` is claimable.


Where to Go Next

## Where to Go Next

- Learn **Proof of Personhood**

    ---

    Where the `PopRules` contract reads the PoP tier from — the App-side mechanism that produces Full and Lite registrations.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-app/pop/)

- Guide **Register and Publish**

    ---

    The Product-side how-to that consumes the PopRules check — registering a `.dot` name and seeing the deposit or free-tier outcome.

    [:octicons-arrow-right-24: Get Started](/apps/deploy-your-app/)


Introduction

## Introduction

This page tracks the current TestNet contract addresses for the dotNS deployment on Paseo. A Product or tool that wants to interact with the registry directly on TestNet needs these addresses; the higher-level CLI and Polkadot Product SDK surfaces resolve them internally, but anyone integrating below those layers can look up what to call here.

!!! warning "Provisional"
    The current TestNet contract addresses are still being finalized as the dotNS deployment stabilizes. Addresses can change across redeployments during this window. The table below will be populated and kept in sync as the deployment is confirmed; until then, the [CLI](/reference/apps/infrastructure/dotns/cli/) and the [Register and Publish](/apps/deploy-your-app/) flow target the current deployment automatically, and most developers should rely on those rather than calling contracts directly.


Contract Address Table

## Contract Address Table

| Contract    | Responsibility                                                    | Paseo TestNet Address |
|:------------|:------------------------------------------------------------------|:----------------------|
| `Registry`  | Holds `(namehash → record)` mappings; gates writes per-record.    | _TBD_                 |
| `Resolver`  | Read-side query surface for name records.                         | _TBD_                 |
| `Records`   | Stores `contenthash`, owner, and per-name administrative fields.  | _TBD_                 |
| `Registrar` | Orchestrates registration: PopRules check, fee collection, write. | _TBD_                 |
| `PopRules`  | Evaluates a proposed registration against the pricing ladder.     | _TBD_                 |
| `Deposit`   | Manages deposits paid by open-tier registrations.                 | _TBD_                 |
| `Transfer`  | Handles owner-changes for an existing name.                       | _TBD_                 |
| `Renewal`   | Handles renewals where they apply.                                | _TBD_                 |
| `Admin`     | Governance-routed operations (reserved names, contract upgrades). | _TBD_                 |

Addresses will appear in this table as the deployment is confirmed. In the meantime, the SDK and CLI resolve the right targets automatically.


How to Use These Addresses

## How to Use These Addresses

For Products that need to read name resolution data directly (most don't — the chain client surface and the resolution code in each Host handle this), point your typed chain client at the resolver contract address using the standard PAPI descriptor for Asset Hub. The query is a standard contract call; the resolver returns the record fields you read against.

For tools or batch jobs that need to mutate state (a CI pipeline registering a name on every release, for example), use the [`@parity/dotns-cli`](/reference/apps/infrastructure/dotns/cli/) instead of building contract calls by hand. The CLI handles the encoding, the PopRules pre-check, and the signing path consistently.


Where to Go Next

## Where to Go Next

- Learn **CLI**

    ---

    The command-line surface that targets these contracts automatically.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/cli/)

- Learn **Architecture**

    ---

    What each contract in the table above is responsible for and how they cooperate.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/architecture/)


Introduction

## Introduction

A `.dot` name is owned by an account on Asset Hub, and that ownership is transferable. A transfer changes _who controls the name's record_ — who can update where it points (its `contenthash`), sell it on, or set administrative fields — without changing the name itself or what it currently resolves to.

This page documents the conceptual transfer flow and the rules dotNS enforces on it.

!!! warning "Provisional"
    The exact dispatch path for a name transfer (which contract, which signed extrinsic, the precise parameter shape), the supported acceptance / rejection mechanics on the receiving side, and any time-locked or escrow variants of transfer are still being finalized. This page documents the conceptual model; the operational reference will be added once confirmed.


What Changes on Transfer

## What Changes on Transfer

A transfer modifies one field of the name's record: the _owner_. Specifically:

- The new owner becomes the account that can sign updates to the name's record (changing the `contenthash`, transferring again, setting fields).
- The name itself — the dotted string the user sees — does not change.
- The currently-attached `contenthash` does not change. Users navigating to the name continue to see the same Product bundle they saw before, unless and until the new owner updates it.
- The PoP tier the original owner used to qualify for the name (Full or Lite tier eligibility) does _not_ transfer with the name. The new owner inherits the name regardless of their own PoP tier, but any future renewal-time or PopRules-evaluated operations are checked against the new owner's status.


When the Tier Lock Matters

## When the Tier Lock Matters

The "PopRules-checked operations" caveat above matters most for Lite-to-Full migration reservations. If a PoP Lite holder registered `alice01.dot` and consequently has `alice.dot` reserved for 12 weeks, that reservation is tied to the _original_ account, not to the name's record. Transferring `alice01.dot` to another account does not transfer the reserved `alice.dot` claim. Reservations are not transferable; the original holder either claims or forfeits the reservation themselves.


What a Product Should Know

## What a Product Should Know

A Product reading a name's record from chain state should treat the owner field as _mutable_. A name pointing at the Product today may be transferred to a new owner tomorrow; the new owner may update the `contenthash` to a different Product. Products that depend on a specific name (linking to it, referencing it from on-chain state) should verify the `contenthash` at use, not cache the assumption that "name X points at this Product forever."


Where to Go Next

## Where to Go Next

- Learn **Name Mechanism**

    ---

    The resolution flow that turns a name into bytes — what a Host actually does between the user typing a `.dot` and a Product loading.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/name-mechanism/)

- Learn **Architecture**

    ---

    The contract responsibilities split, including which contract handles the transfer dispatch.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/dotns/architecture/)


Introduction

## Introduction

A HOP transfer is built from a sequence of single-chain hops, each one taking the transfer one step closer to its destination. The protocol's job is to make a sequence of single-chain hops behave like a single coherent operation — atomic enough for the sender to reason about, with proofs that the intermediate state was correctly cleared as the transfer moved through.

This page documents the conceptual model: what a hop is, how multi-hop routing is constructed, and how the verifier model works at a high level.

!!! warning "Provisional"
    The exact wire format of a HOP message, the runtime extrinsics that initiate and consume hops, the verifier interface, and the per-chain integration surface are still being finalized. This page covers the conceptual model only; the protocol-level reference will be added once the surface stabilizes.


What a Single Hop Is

## What a Single Hop Is

A single hop moves a transfer from one chain to one adjacent chain. The hop carries:

- **The payload**: The asset and amount, or the message being moved.
- **A proof**: Evidence that the source chain has authorized the hop (typically a signed XCM-style message from the source chain's account holding the funds).
- **Routing information**: Where the hop should land next, plus any constraints or fees the next hop should respect.

The receiving chain on the other side of a hop validates the proof, accepts the payload, and either holds the funds locally (if it is the destination) or constructs the next hop forward.


How Multi-Hop Routing Is Constructed

## How Multi-Hop Routing Is Constructed

A multi-hop transfer is a chain of single hops — chain A → chain B → chain C, for example, where A is the sender's chain, C is the destination, and B is an intermediate routing chain.

The routing can be:

- **Sender-specified**: The sender constructs the full hop sequence at dispatch time and signs the whole thing.
- **Router-determined**: The sender specifies only the destination, and intermediate chains determine the next-hop routing dynamically.

In both modes, each hop carries enough proof for the receiving chain to validate the previous hop independently, so the chain doesn't need to trust the routing chain's word about what happened upstream.


The Verifier Model

## The Verifier Model

The verifier is the component that checks the cryptographic correctness of each incoming hop. It receives the payload, the proof, and the routing context, and produces either an "accept" or "reject" outcome. The chain's HOP integration calls into the verifier for every incoming hop; only accepted hops modify chain state.

The verifier abstracts the cryptography from the chain's HOP integration, so different verifier implementations can plug in without rewriting the per-chain integration code. The current `NoopVerifier` is a development stand-in that always accepts — useful for testing the protocol flow without the cryptographic overhead, but not suitable for production. A production verifier is forthcoming.


What a Product Sees

## What a Product Sees

A Product dispatching a HOP transfer through a higher-level surface (Coinage, or a future payment-routing primitive that uses HOP underneath) sees a single `signAndSubmit`-style call that resolves when the transfer completes — or fails — at the destination. The multi-hop machinery underneath is not directly exposed to the Product code; it is the chain's HOP integration that orchestrates the hops, and the Product's UI shows the result the destination reports back.


Where to Go Next

## Where to Go Next

- Learn **Sender Journey**

    ---

    What a participant sending a HOP transfer sees — dispatch, tracking, and finalization on the destination.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/sender/)

- Learn **Recipient Journey**

    ---

    What a participant receiving a HOP transfer sees on the destination chain.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/recipient/)


Introduction

## Introduction

HOP is Polkadot's cross-chain hop protocol — a mechanism for moving assets and messages between chains in the Polkadot ecosystem with more flexibility than a plain XCM transfer. The use case is *"hop a transfer through one or more intermediate chains to reach its destination,"* with HOP handling the per-hop routing, proofs, and cleanup of intermediate state.

For most Product developers, HOP is not something you will reach for in day-one flows. The standard payment patterns — `Balances.transfer_keep_alive` for merchant flows, [Coinage](/reference/apps/infrastructure/pop/pallet-coinage/) for personhood-aware payments — cover the common cases without needing HOP. HOP becomes relevant when a Product crosses chain boundaries in a way standard XCM does not cleanly handle.

!!! warning "Current state caveats"
    HOP is being actively built and three caveats apply to integrations against the current code:

    - **`NoopVerifier` is not production-ready**: The current verifier implementation is a development stand-in. Production-grade verification is forthcoming.
    - **The repository README is out of date**: Where the README and this reference disagree, this reference reflects the intended direction; the README will be updated separately.
    - **`pallet-hop-promotion` status is evolving**: The promotion pallet that pairs with HOP for certain flows is in flux; integrations should not depend on its current shape.

    These notes will be removed from this page as each item resolves.


Where HOP Fits

## Where HOP Fits

Three places HOP shows up in a Product context:

- **As a building block under cross-chain payments**: Coinage and other payment flows can route through HOP underneath when the sender and recipient are on different chains. The Product surface (Coinage, `Balances.transfer_keep_alive`) is what a Product calls; HOP is the layer beneath that makes the cross-chain part work.
- **As a primitive for cross-chain messaging beyond payments**: Moving non-asset payloads (state references, capability handles) across chain boundaries in flows that need more flexibility than plain XCM.
- **As a target for node-operator and runtime-developer work**: Running a HOP-enabled node, integrating HOP into a new Substrate chain. These node-operator and SDK-integration paths are forthcoming separately.


Where to Go Next

## Where to Go Next

- Learn **How It Works**

    ---

    The conceptual protocol — what a "hop" is, how multi-hop routing is constructed, and the verifier model.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/how-it-works/)

- Learn **Sender Journey**

    ---

    The sender side of a HOP transfer: building, dispatching, and tracking a multi-hop send.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/sender/)

- Learn **Recipient Journey**

    ---

    The recipient side: receiving a HOP transfer that landed on a chain via one or more hops.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/recipient/)


Introduction

## Introduction

This page documents the recipient side of a HOP transfer: what a participant or chain receiving the final hop sees, how the destination chain validates the incoming proof, and what settles when the validation passes.

For the protocol mechanics underneath, see [How It Works](/reference/apps/infrastructure/hop/how-it-works/). For the sender's view, see [Sender Journey](/reference/apps/infrastructure/hop/sender/).

!!! warning "Provisional"
    The exact recipient-side event surface (what events the destination emits when a HOP transfer lands, the subscription primitive for those events, the state-change semantics), and any accept-or-decline mechanics on the recipient's side are still being finalized. This page documents the conceptual flow; the per-event reference will be added once the surface stabilizes.


The Flow at a Glance

## The Flow at a Glance

From the recipient's perspective:

1. **An incoming hop lands**: The destination chain receives the final hop with its payload and proof.
2. **The verifier validates**: The chain's HOP integration calls the configured verifier; only an accepted proof proceeds to settlement.
3. **State settles**: The destination chain applies the payload's effect — crediting the recipient's account for an asset transfer, recording the message for a message-passing flow, or whatever the payload prescribed.
4. **The destination emits a finalization event**: The event is what tells the sender (and the recipient's UI, if any) that the transfer completed.

Importantly, the recipient does _not_ typically have to explicitly accept the transfer — settlement happens automatically when the verifier accepts. Where two-sided acceptance is needed (a Coinage-style flow where the recipient can decline), that semantics is layered on top of HOP by the higher-level pallet, not built into HOP itself.


What the Recipient's Product Sees

## What the Recipient's Product Sees

If the recipient is a user of a Polkadot Product, the Product subscribes to the relevant chain state on the destination chain. When the HOP transfer settles:

- The user's balance (or other state) updates as the destination chain's storage changes.
- The Product UI surfaces the change to the user — typically as an arrived transfer or an updated state value.

For asynchronous receive flows, the Product builds against the destination chain's chain-client surface — see [Read Chain State](/apps/build/read-chain-state/) for the pattern.


Where to Go Next

## Where to Go Next

- Learn **How It Works**

    ---

    The protocol mechanics — single hops, multi-hop routing, the verifier model that gates settlement.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/how-it-works/)

- Guide **Read Chain State**

    ---

    The Product-side how-to for subscribing to chain state — the surface a recipient's Product uses to observe HOP-driven state changes.

    [:octicons-arrow-right-24: Get Started](/apps/build/read-chain-state/)


Introduction

## Introduction

This page documents the sender side of a HOP transfer: what a participant who initiates the send does, what they see as it routes, and how they observe whether it landed.

For the protocol mechanics underneath, see [How It Works](/reference/apps/infrastructure/hop/how-it-works/). For the recipient's view, see [Recipient Journey](/reference/apps/infrastructure/hop/recipient/).

!!! warning "Provisional"
    The exact sender-side dispatch extrinsics, the tracking surface (events emitted at each hop, subscribable status), and the finalization signal a sender observes are still being finalized. This page documents the conceptual flow; the per-call reference will be added once the surface stabilizes.


The Flow at a Glance

## The Flow at a Glance

From the sender's perspective:

1. **Build the hop sequence**: Either specify the full route (sender-specified routing) or specify only the destination and let routing chains determine the intermediate hops dynamically.
2. **Sign and dispatch**: A single signed transaction on the sender's chain initiates the send. The signing uses the standard mediated-signing flow — the user approves on the paired App per the usual model.
3. **Watch the hops progress**: Each hop emits an event on the chain it landed on; the sender's UI (or backend, if the sender is a service) can subscribe to those events to track progress.
4. **Observe finalization**: When the transfer lands on the destination chain, the destination emits a finalization event. The sender's flow can resolve at that point — typically by updating UI, posting a confirmation, or triggering the next step in a larger workflow.


What Can Go Wrong

## What Can Go Wrong

The two common failure modes a sender's UI should handle:

- **Mid-route rejection**: A hop fails verification on an intermediate or destination chain (the verifier rejects the proof, the receiving chain refuses for policy reasons, fees are insufficient). The funds typically remain reclaimable on the chain where the failure occurred; the sender's UI should make recovery visible.
- **Timeout / loss of tracking**: A hop succeeds but the sender's monitoring loses visibility (the sender's node was offline during the relevant events). The funds are still where the chain says they are; the sender's UI should recover by reading the destination's state directly rather than assuming the worst from missing events.


Where to Go Next

## Where to Go Next

- Learn **How It Works**

    ---

    The protocol mechanics underneath the sender flow — single hops, multi-hop routing, the verifier model.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/how-it-works/)

- Learn **Recipient Journey**

    ---

    The receiving side of a HOP transfer.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/hop/recipient/)


Introduction

## Introduction

Proof of Personhood (PoP) is Polkadot's privacy-preserving way to confirm a user is a real human, without exposing _which_ human. A user completes PoP once (in the [Polkadot App](/reference/apps/hosts/polkadot-app/)); from then on, a single proof unlocks personhood-gated features — the TestNet faucet, short `.dot` names, alias-gated checks inside a Polkadot Product, and on-chain payments routed through personhood-aware pallets.

For a Product developer, PoP shows up in two places:

- **As a primitive your Product calls into**: Through the Product SDK your Product requests an alias for the current user, has the user prove control of that alias against a challenge, and gates features on the result. The Polkadot App is where the proving happens; your Product never sees the underlying biometric or the user's identity record.
- **As a runtime origin your Product dispatches under**: Polkadot's PoP pallets accept calls under the `under_alias` origin, so your Product can submit on-chain operations that resolve to the user's alias inside the called pallet — pallet state stays unlinkable to the underlying account.

This reference is organized into two halves: the mechanism (Ring-VRF, aliases, the unlinkability property, how `under_alias` works) on its own page, and per-pallet reference for the pallets a Product is most likely to dispatch into.


The Mechanism

## The Mechanism

[Ring-VRF and Aliases](/reference/apps/infrastructure/pop/ring-vrf-and-aliases/) is the conceptual deep dive: how the PoP cryptography produces unlinkable per-Product aliases, what `under_alias` is at the runtime layer, and the privacy property the whole stack delivers.


The Pallets

## The Pallets

| Pallet                                                                   | What It Covers                                                                                |
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| [`pallet-people`](/reference/apps/infrastructure/pop/pallet-people/)     | Personhood registration, alias-issuing, and the `under_alias` runtime origin. The foundational pallet the rest of the set depends on. |
| [`pallet-game`](/reference/apps/infrastructure/pop/pallet-game/)         | Personhood-gated on-chain games and randomized selection flows.                                                                       |
| [`pallet-score`](/reference/apps/infrastructure/pop/pallet-score/)       | Personhood-anchored reputation and scoring primitives.                                                                                |
| [`pallet-identity`](/reference/apps/infrastructure/pop/pallet-identity/) | The identity record on People Chain associated with a PoP account.                                                                    |
| [`pallet-ubc`](/reference/apps/infrastructure/pop/pallet-ubc/)           | Universal Basic Capacity — the per-person on-chain capacity primitives.                                                               |
| [`pallet-coinage`](/reference/apps/infrastructure/pop/pallet-coinage/)   | The personhood-aware peer-to-peer payment surface behind the App's Coinage feature.                                                   |


Where to Go Next

## Where to Go Next

- Learn **Ring-VRF and Aliases**

    ---

    The cryptographic and runtime mechanism — how PoP produces unlinkable per-Product aliases, what `under_alias` is, and the privacy property the whole stack delivers.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/pop/ring-vrf-and-aliases/)

- Learn **pallet-people**

    ---

    The foundational pallet of the PoP set — registration, alias-issuing, and the `under_alias` runtime origin.

    [:octicons-arrow-right-24: Reference](/reference/apps/infrastructure/pop/pallet-people/)


Introduction

## Introduction

`pallet-coinage` is the on-chain pallet behind the [Polkadot App's Coinage feature](/reference/apps/hosts/polkadot-app/coinage/) — the peer-to-peer payment surface that lets a user send funds to another verified person, with privacy properties beyond what a standard `Balances.transfer_keep_alive` provides.

Two properties differentiate Coinage from a standard transfer at the pallet level:

- **Personhood-aware addressing**: Sends can target a recipient identified by their personhood identity rather than by their account address; the pallet resolves the address from the personhood claim.
- **Privacy-preserving by default**: Where appropriate, the pallet routes the transfer through alias / Ring-VRF surfaces so the on-chain trail does not directly link the sender's account to the recipient's account in the same way a public `Balances.transfer_keep_alive` does.

!!! info "Underlying asset: HOLLAR today, pUSD later"
    `pallet-coinage` is backed by a stablecoin on Asset Hub (configured via `UnderlyingAssetId`). Today that asset is HOLLAR; the system is designed to migrate to pUSD when pUSD lands. The pallet itself works today against HOLLAR — the underlying asset is loaded into recyclers via `load_recycler_with_external_asset` and unloaded via the corresponding `unload_recycler_into_external_asset` variants. The dispatch surface stays the same across the HOLLAR → pUSD transition.

!!! warning "Provisional"
    The complete enumeration of the `pallet-coinage` dispatch surface (every extrinsic, parameter shape, event, and error) is still being finalized. This page documents the conceptual model and the operation families; per-extrinsic specifics will be added once confirmed.


Conceptual Surface

## Conceptual Surface

The pallet's operations cluster into four families:

- **Transfer**: A two-step "pull" mechanic. The sender shares the private key of the coin(s) being sent over an off-chain channel (typically the Polkadot App's encrypted chat). The receiver derives a fresh key from their own mnemonic and calls `transfer(to)` to move each coin to that new key. The coin's age increments by 1. Transfer is always free.
- **Split**: A user splits one coin into any combination of smaller coins whose values sum to the original. All output coins inherit `originalAge + 1`. Split is always free.
- **Recycle (load / unload)**: The privacy core. A user loads a coin (or equivalent stablecoin) into a recycler ring, waits for other entries to join, then unloads with a Ring-VRF proof — minting a fresh coin or withdrawing the backing stablecoin, with no on-chain link to the deposit. Loading is free; unloading is the only charged operation in the system.
- **Onboard / offboard**: Conversion between coins and the backing stablecoin. Onboarding loads stablecoin into a recycler and unloads anonymously into fresh coins. Offboarding does the reverse. A `direct_offboard_coin_into_external_asset` fast path skips the recycler for freshly-minted (age-0) coins that do not need anonymity.


Relationship to Coinage in the App

## Relationship to Coinage in the App

The App's Coinage feature is the user-facing surface; `pallet-coinage` is the on-chain pallet that surface dispatches into. A Product developer who wants Coinage-style payments in their own Product invokes `pallet-coinage` via the standard signing surface (with the user approving each transaction on their App, as with all signed actions).

For the App-side feature reference see [Coinage in the Polkadot App](/reference/apps/hosts/polkadot-app/coinage/).


Pallet Surface

## Pallet Surface

The transfer, split, load, and unload extrinsics, the coin storage, and the recycler ring data are enumerated here.

!!! warning "Provisional"
    Parameter shapes, event names, and error variants are pending Parity confirmation. The operation set below reflects the design as documented in the briefing.

| Symbol                                                                                | Kind        | Notes                                                                     |
|:--------------------------------------------------------------------------------------------------------------------------------|:------------|:--------------------------------------------------------------------------|
| `transfer`                                                                                | Extrinsic   | Free; pull-mechanic — receiver moves the coin                             |
| `split`                                                                                | Extrinsic   | Free; one coin into many summing to its value                             |
| `load_recycler_with_coin`                                                                                | Extrinsic   | Free; coin origin; deposits a coin into the recycler ring                 |
| `load_recycler_with_external_asset`                                                                                | Extrinsic   | Free; signed origin; deposits backing stablecoin                          |
| `unload_recycler_into_coin`                                                                                | Extrinsic   | Ring-VRF proof; mint a fresh age-0 coin                                   |
| `unload_recycler_into_external_asset`                                                                                | Extrinsic   | Ring-VRF proof; withdraw backing stablecoin                               |
| `unload_recycler_into_coins`                                                                                | Extrinsic   | Unload + split in one op; lifts power-of-two restriction                  |
| `unload_recycler_into_external_asset_non_anonymous`                                                                             | Extrinsic   | Signer pays fee directly; identity visible                                |
| `direct_offboard_coin_into_external_asset`                                                                                | Extrinsic   | Fast path for age-0 coins; bypasses the recycler                          |
| `pay_for_recycler_unload_fee_token_with_coin`                                                                                | Extrinsic   | Paid path for users out of free unload tokens                             |
| `pay_for_recycler_unload_fee_token_with_native`                                                                                | Extrinsic   | Paid path; DOT                                                            |
| `pay_for_recycler_unload_fee_token_with_stable`                                                                                | Extrinsic   | Paid path; stablecoin                                                     |
| `clean_recycler` / `clean_consumed_free_token` / `clean_paid_unload_token_ring` / `delete_expired_paid_unload_token_collection` | Extrinsic   | Offchain-worker-authorised cleanup                                        |
| `CoinsByOwner`                                                                                | Storage map | Per-public-key coin record (storage is one entry per key)                 |
| `UnderlyingAssetId` / `UnderlyingAssetUnit`                                                                                | Constant    | The backing stablecoin id and base unit ($0.01); HOLLAR today, pUSD later |
| `MinimumExponent` / `MaximumExponent`                                                                                | Constant    | Valid coin denomination range (0–14 = $0.01–$163.84)                      |
| `MaximumAge` / `MinimumAgeForRecycling`                                                                                | Constant    | Coin age limits before mandatory recycling                                |
| `UnloadTokenAllowancePerTimePeriodForPeople` / `…ForLitePeople`                                                                 | Constant    | Free unload-token budget per period                                       |
| `RecyclerExpirationTime`                                                                                | Constant    | Lifetime of a full recycler ring before cleanup                           |


Where to Go Next

## Where to Go Next

- Learn **Coinage in the Polkadot App**

    ---

    The App-side feature reference — the user-visible surface that dispatches into this pallet.

    [:octicons-arrow-right-24: Reference](/reference/apps/hosts/polkadot-app/coinage/)