You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Full usernames registered after the migration exist only on Asset Hub / dotNS, but the mobile app can only resolve usernames by accountId (and subscribe to changes) via People Chain — which full usernames never reach.
Username management is migrating from People Chain (pallet_resources, written by the Identity Backend during attest) to dotNS on Asset Hub. The two flows now behave differently:
Lite username (claim): the app calls the Identity Backend, which dual-writes — attest on People Chain andpallet_dotns_gateway::reserve_name on Asset Hub. Lite usernames therefore exist on both chains.
Full username (registration/claim as full person): the app submits pallet_dotns_gateway::register_namedirectly on Asset Hub (V5 general transaction, AsDotnsGateway extension). The Identity Backend is not involved, and nothing writes the full username to People Chain.
The app's only practical way to resolve usernames by accountId — and to subscribe to changes — is still People Chain:
Resources::Consumers[accountId] is a single storage read keyed by the account, returning ConsumerInfo { liteUsername, fullUsername, identifierKey (chat ECDH key) }, and it works with standard substrate storage subscriptions (no polling).
The app uses it for: own username status (with on-chain subscription), resolving contacts by accountId, chat identity (the ECDH identifierKey), incoming chat requests, backup/recovery of the username after reinstall or on a new device.
On the Asset Hub side there is no equivalent API:
pallet_dotns_gateway storage offers only:
LiteLabelOwner: label → owner — the wrong direction for accountId lookup;
AccountAlias: accountId → alias — proves that the account has an alias (we use it as a "has full username" flag via subscription), but does not contain the username itself.
The dotNS contract can answer reverse lookups only via a chain of 5–6 sequential view calls (controller → protocolRegistry() → get("storeFactory") → getLabelStore(h160) → getLabels(), plus pendingClaim(s) for the cold path — reference implementation: resolve_labels in paritytech/host-rust-core#426). These are one-shot eth_call-style reads: not subscribable through substrate storage subscriptions, so the app would have to poll.
Contract events (NameRegistered, BaseNameClaimed, LiteNameReserved, … in IDotnsPopController.sol, indexed by user + labelhash) would allow eth_getLogs polling, but that is still polling; eth_subscribe is only available from stable2606.
Consequences:
Full usernames are invisible to other users. Contacts are resolved via People Chain, where a post-migration full username never lands. A full person is shown to peers by their lite (or stale legacy) name.
The user's own full username string cannot be read back from chain. The app currently merges: PC ConsumerInfo (name strings) + AH AccountAlias existence flag + a locally stored full-name string. On reinstall or a second device, recovery reads People Chain only — the full username is unrecoverable; the account degrades to its lite name.
Chat identity depends on PC. The ECDH chat key is read from PC ConsumerInfo, even though dotNS also stores it in the registry.
Circular dependency on the "temporary" dual-write. The spec says PC data duplication is temporary, "solely for backwards compatibility till the app is upgraded". But the app cannot be upgraded off People Chain until Asset Hub offers resolve-by-accountId (ideally subscribable); and People Chain writes cannot be decommissioned until the app migrates. If the backend stops the PC dual-write before this lands, username resolution and recovery break entirely.
Proposal
A queryable — and ideally subscribable — accountId → username(s) source on Asset Hub. Options, from our perspective:
Pallet-level storage map in pallet_dotns_gateway (accountId → lite/full labels, or at least the full label). This is the best fit for mobile: one storage key per account, works with existing substrate storage subscriptions, no polling.
How long is the People Chain dual-write guaranteed to stay? Every release we ship in the meantime deepens the dependency on it (recovery, chats, contact resolution).
Related: #214 (gateway cleanup umbrella), #215, #216 (names queryable by address), #217 (profileOf(address)); paritytech/host-rust-core#426 — the reference host is making the same PC → AH dotNS resolution move, so resolve-by-address is needed beyond mobile.
App-side dependency points (Android): RealUsernamesOfAccountUseCase (own status: PC ConsumerInfo + AH AccountAlias flag + local string), RealResolveUsernamesUseCase (contacts via PC resolveConsumers), RealRecoverUsernameUseCase (recovery via PC only), UsernameOnChainUpdater (PC storage subscription), AccountAliasUpdater (AH AccountAlias subscription — flag only), chats (SyncContactUsernameUseCase, IncomingChatRequestProcessor, StartChatDataUseCase), backup (BackupFoundInteractor).
Acceptance criteria
Given an accountId (or its h160), the app can obtain the account's lite and full usernames from Asset Hub without People Chain involvement.
Username changes for an account are observable without client-side interval polling (substrate storage subscription), or a documented polling contract (eth_getLogs on gateway events) is confirmed as the intended mechanism.
The chat ECDH key is obtainable from Asset Hub/dotNS by accountId as part of the same lookup.
A stated support window for the People Chain dual-write that the app team can plan releases against.
Component
Proof of Personhood
Priority
P1
Summary
Full usernames registered after the migration exist only on Asset Hub / dotNS, but the mobile app can only resolve usernames by accountId (and subscribe to changes) via People Chain — which full usernames never reach.
Username management is migrating from People Chain (
pallet_resources, written by the Identity Backend duringattest) to dotNS on Asset Hub. The two flows now behave differently:atteston People Chain andpallet_dotns_gateway::reserve_nameon Asset Hub. Lite usernames therefore exist on both chains.pallet_dotns_gateway::register_namedirectly on Asset Hub (V5 general transaction,AsDotnsGatewayextension). The Identity Backend is not involved, and nothing writes the full username to People Chain.The app's only practical way to resolve usernames by accountId — and to subscribe to changes — is still People Chain:
Resources::Consumers[accountId]is a single storage read keyed by the account, returningConsumerInfo { liteUsername, fullUsername, identifierKey (chat ECDH key) }, and it works with standard substrate storage subscriptions (no polling).identifierKey), incoming chat requests, backup/recovery of the username after reinstall or on a new device.On the Asset Hub side there is no equivalent API:
pallet_dotns_gatewaystorage offers only:LiteLabelOwner: label → owner— the wrong direction for accountId lookup;AccountAlias: accountId → alias— proves that the account has an alias (we use it as a "has full username" flag via subscription), but does not contain the username itself.controller → protocolRegistry() → get("storeFactory") → getLabelStore(h160) → getLabels(), pluspendingClaim(s)for the cold path — reference implementation:resolve_labelsin paritytech/host-rust-core#426). These are one-shoteth_call-style reads: not subscribable through substrate storage subscriptions, so the app would have to poll.NameRegistered,BaseNameClaimed,LiteNameReserved, … inIDotnsPopController.sol, indexed by user + labelhash) would alloweth_getLogspolling, but that is still polling;eth_subscribeis only available from stable2606.Consequences:
ConsumerInfo(name strings) + AHAccountAliasexistence flag + a locally stored full-name string. On reinstall or a second device, recovery reads People Chain only — the full username is unrecoverable; the account degrades to its lite name.ConsumerInfo, even though dotNS also stores it in the registry.Proposal
A queryable — and ideally subscribable —
accountId → username(s)source on Asset Hub. Options, from our perspective:pallet_dotns_gateway(accountId → lite/full labels, or at least the full label). This is the best fit for mobile: one storage key per account, works with existing substrate storage subscriptions, no polling.names permanent & queryable by address,profileOf(address)— lite/full names, chat key, link, tier in a single view call). This solves the query side in one call, but contract views are still not subscribable, so the app would needeth_getLogs/interval polling on top. Workable, strictly worse than (1) for battery/network.Concrete questions:
Related: #214 (gateway cleanup umbrella), #215, #216 (names queryable by address), #217 (
profileOf(address)); paritytech/host-rust-core#426 — the reference host is making the same PC → AH dotNS resolution move, so resolve-by-address is needed beyond mobile.App-side dependency points (Android):
RealUsernamesOfAccountUseCase(own status: PCConsumerInfo+ AHAccountAliasflag + local string),RealResolveUsernamesUseCase(contacts via PCresolveConsumers),RealRecoverUsernameUseCase(recovery via PC only),UsernameOnChainUpdater(PC storage subscription),AccountAliasUpdater(AHAccountAliassubscription — flag only), chats (SyncContactUsernameUseCase,IncomingChatRequestProcessor,StartChatDataUseCase), backup (BackupFoundInteractor).Acceptance criteria
eth_getLogson gateway events) is confirmed as the intended mechanism.