Skip to content

Identity: an Inbox, not a wallet address

Using a wallet address directly as the messenger ID makes three things impossible.

  • Merging one person's several wallets into a single inbox
  • Letting a phone and a laptop hold different keys (you cannot copy an address's private key onto every device)
  • Cutting off only the one device that leaked

XMTP v3 solves this with a three-layer identity model (XIP-46).

flowchart TB
  inbox["Inbox ID<br/>stable identifier, the message destination"]
  w1["Wallet 1 (EOA)"]
  w2["Wallet 2 (smart contract wallet)"]
  i1["installation: phone"]
  i2["installation: laptop"]
  i3["installation: tablet"]
  inbox --> w1
  inbox --> w2
  w1 --> i1
  w1 --> i2
  w2 --> i3
Layer What it is Count
Inbox ID The user's stable identifier. SHA256 of the first wallet address concatenated with a nonce. Messages are addressed to this value, not to an address One per person
identity A wallet linked to the Inbox. Both EOAs (EIP-191 signatures) and smart contract wallets (ERC-1271 signatures) are supported Several per Inbox
installation An Ed25519 key pair created per device (strictly, per client) that installs the app. The actual agent of encryption and decryption 10 active per Inbox

If you lose a device

The Inbox's first identity becomes the recovery address, and only the recovery address can revoke a wallet or a device. That makes it possible to cut off just the lost phone's installation while keeping the identity.

Identity changes come in four operations: CreateInbox, Add, Revoke, and ChangeRecoveryAddress.

Where the 10-installation limit actually bites

An Inbox allows up to 10 active installations. Every sign-in from empty browser storage registers a new installation. So all of the following burn a slot.

  • Signing in from a new browser or an incognito window
  • Signing in again after Clear site data
  • Running E2E tests repeatedly with a fresh profile

Once the limit is reached, Client.create hangs without responding. The symptom is "pressing sign in never advances to the inbox."

On top of that, because MLS keys differ per installation, a new installation cannot decrypt messages sent before it joined the conversation. The ciphertext is still on the network, but there is no key to open it. That is what the "my conversation disappeared" symptom really is in Umul; the details and Umul's response are in Message History.

Identity changes are recorded on chain

Identity changes — adding a wallet, adding a device, revoking — are recorded as blockchain transactions rather than as ordinary messages stored on nodes. The decentralized node implementation (xmtpd) outright rejects an Identity Update arriving on the message path and accepts it only through a call to the IdentityUpdateBroadcaster contract.

An indexer reads those events back to build an "address → Inbox ID" mapping, and the "look up the peer" step just before starting a conversation reads that mapping in reverse.

What stays on chain and what stays on nodes is tabulated in Encryption and Delivery.