Skip to content

Accounts and Signing

Introduction

More than one account is in play when you build and deploy a Polkadot Product, and they are not always the same account. Getting them confused is the most common way to hit a no allowance set for account error: you fund or authorize one account, then sign with a different one. This page explains which component holds which key, which account actually signs, and how to keep them aligned.

Who Holds What

  • The phone (Polkadot App): Holds the user's root private key and the secret for every per-Product account derived from it. All signing happens here. The key never leaves the device.
  • The Host (Polkadot Desktop or Web): Holds no keys. It relays signing requests to the paired phone and shows the result.
  • The playground CLI: What it holds depends on the signer mode you choose, covered next.

The Account That Signs a Deploy

playground deploy signs with a different account depending on the signer mode:

  • --signer phone (the choice to make for a deploy you intend to keep; omit the flag and pg deploy prompts you): The deploy is signed by a product account derived from the phone's root key, scoped to your Product. The CLI holds only a paired session; the secret stays on the phone, which approves each step. The CLI does not create its own account in this mode.
  • --signer dev --suri <uri>: The CLI signs with a local development key derived from the URI you pass (for example, //Alice or a mnemonic). This account is unrelated to the phone. No phone approvals happen.
  • --signer dev with no --suri: Falls back to a shared, publicly known development mnemonic. Anyone can control this account; never use it for a deploy you want to keep.

Dev-signer deploys are owned by the dev account

A Product deployed with --signer dev is owned by that development key, not by you. Use the phone signer for anything you intend to keep or hand to real users.

Product Accounts Are Per Product

A product account is derived deterministically from ["product", productId, derivationIndex], so the account you get depends on the productId and index in play:

  • Inside a Host, your frontend derives its productId from where it is loaded: localhost maps to playground.dot, a <name>.dot.li gateway URL maps to <name>.dot, and otherwise it falls back to playground.dot. The derivation index is 0.
  • The CLI session derives its own product account from the identifier it was paired under.

The consequence: the account your running frontend signs with, and the account the CLI deployed under, are the same only if their productId and index match. A Product loaded from localhost (deriving under playground.dot) uses a different account than the same Product loaded from my-app.dot.li (deriving under my-app.dot). See Identity for the full derivation model.

Why This Causes no allowance set for account

Storage and messaging allowances are granted per account. A missing allowance is rejected independently of your token balance: even with enough PAS to cover fees, the service rejects the request if the signing account has no allowance.

So the failure is almost always an account mismatch: you granted the allowance (or storage authorization) to one account, but the account that actually signed was a different one — a dev key instead of the phone account, or a product account derived under a different productId than you expected. The fix is to grant the allowance to the account that actually signs, and to keep the productId consistent between where you request the allowance and where you sign. See the troubleshooting entry for the step-by-step resolution.

See the Signing Address

Before granting an allowance, confirm which account will sign:

  • From the CLI: Run pg status. It prints the product account paired with your phone in both encodings — the SS58 address and its H160 (EVM) form — along with its PAS and PGAS balances and the state of its Bulletin allowance. It is read-only: it signs nothing and submits no transactions, so it is safe to run at any point. pg login prints the same two addresses when a session is established.
  • In a Host: A Product running inside Polkadot Desktop or Web can read its product account through the signer package (getProductAccount), which returns the account's SS58 address and its H160 (EVM) form. Surfacing that address in your Product's own UI during development is the most reliable way to know what your frontend is signing with.

The two addresses are one key

pg status reports the SS58 and the H160 as separate rows, but they are two encodings of the same product account, not two accounts. Fund and authorize the SS58 form; pallet-revive contracts see the H160 form as caller().

The CLI account is not always your frontend's account

pg status reports the account derived under playground.dot/0. A Product loaded from a deployed name derives under that name instead, so its account differs from the one the CLI shows. Check both when an allowance lands somewhere unexpected.

Where to Go Next

  • Learn Allowances and Permissions


    What an allowance authorizes, and how to grant it to the right account.

    Allowances and Permissions

  • Learn Identity


    The per-Product account derivation model and why accounts differ across Products.

    Identity

  • Guide Get TestNet Tokens


    Fund the signing account and grant it the service allowances it needs.

    Get TestNet Tokens

Last update: September 2, 2026
| Created: September 2, 2026