Why
Wallet addresses are the worst of both identity worlds: too sticky to be anonymous, too loose to be an account. The person is many wallets (hot, cold, work, mobile, the one from 2021); sometimes the wallet is many people (a team multisig, a shared ops key). Every product question — whose purchase history, whose loyalty points, who can the support desk talk to — lands on a mapping the chain does not provide.
Sign-In-With-Ethereum narrows this but does not close it: a valid SIWE session proves the presenter controls the key now — it says nothing about whether that presenter is the same human as yesterday, or the only one. So the account model is an application design decision with real security edges: wallet linking is an authorization graph, and the unlink operation is where account-takeover hides. Getting it wrong is how a stolen hot wallet becomes a stolen whole account.
How it works
An account service, two linked wallets, and the three edge cases that define the model.
PoC
A small app (SIWE via viem, SQLite accounts): create an account with wallet A, link wallet B by signing a challenge from an already-authenticated session. Then implement and test the edges: (1) unlink policy — require the action from the remaining wallet, and add a time-locked grace period so a thief who links their wallet cannot immediately evict yours; (2) history — purchases stay with the account, not the wallet, and show what unlink means for them; (3) shared wallet — wallet B links to a second account and the code must choose: reject, allow-many, or transfer-with-consent. Each choice is a policy table row with a test.
What it proves
Account linking looks like a convenience feature and is actually an authorization system: every link is a granted capability, every unlink a revocation, and the timing rules between them are the account-takeover surface. The chain gives you a permissionless key graph; the product must decide, explicitly, what a person is.