Workspace IndexDev Notes › The wallet is not the user

#63PoC

The wallet is not the user

One person holds five wallets; one wallet is shared by a team; SIWE proves control of a key, not identity of a person. An account model that assumes wallet = user breaks linking, history and support the moment real users arrive.

Build an app account that links two wallets via SIWE, then answer the questions that immediately appear in code: which wallet may unlink the other, what happens to history on unlink, and what a shared wallet does to the model.

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.

← All Dev Notes · Workspace Index · Top ↑

지갑은 사용자가 아니다

한 사람이 지갑 다섯을 갖고, 한 지갑을 팀이 공유하며, SIWE 는 키의 통제를 증명하지 사람의 신원을 증명하지 않습니다. 지갑 = 사용자를 가정한 계정 모델은 실제 사용자가 오는 순간 연결·이력·CS 에서 깨집니다.

SIWE 로 지갑 둘을 연결하는 앱 계정을 만들고, 즉시 나타나는 질문들을 코드로 답합니다: 어느 지갑이 다른 지갑을 해제할 수 있는가, 해제 시 이력은 어떻게 되는가, 공유 지갑은 이 모델을 어떻게 흔드는가.

지갑 주소는 두 신원 세계의 나쁜 점만 모았습니다: 익명이기엔 너무 끈적하고, 계정이기엔 너무 헐겁습니다. 사람은 여러 지갑(핫, 콜드, 업무용, 모바일, 2021년의 그것)이고, 때로 지갑이 여러 사람(팀 멀티시그, 공유 운영 키)입니다. 모든 제품 질문 — 누구의 구매 이력, 누구의 포인트, CS 데스크는 누구와 이야기하는가 — 이 체인이 제공하지 않는 매핑 위에 떨어집니다.

Sign-In-With-Ethereum 은 이것을 좁히지만 닫지 못합니다: 유효한 SIWE 세션은 제시자가 지금 그 키를 통제한다는 것만 증명합니다 — 어제의 그 사람과 같은지, 유일한지에 대해서는 아무 말도 하지 않습니다. 그래서 계정 모델은 실제 보안 모서리를 가진 애플리케이션 설계 결정입니다: 지갑 연결은 권한 그래프이고, 연결 해제가 계정 탈취가 숨는 곳입니다. 이것을 틀리면 도난당한 핫월렛이 도난당한 계정 전체가 됩니다.

동작 방식

계정 서비스 하나, 연결된 지갑 둘, 그리고 모델을 정의하는 모서리 셋.

PoC

작은 앱(viem 으로 SIWE, SQLite 계정): 지갑 A 로 계정 생성, 이미 인증된 세션에서 챌린지에 서명해 지갑 B 를 연결. 그다음 모서리들을 구현하고 테스트합니다: (1) 해제 정책 — 남는 지갑 쪽에서 실행하게 하고, 도둑이 자기 지갑을 연결하자마자 당신 지갑을 쫓아내지 못하도록 시간 잠금 유예를 추가; (2) 이력 — 구매는 지갑이 아니라 계정에 남고, 해제가 그것에 무엇을 뜻하는지 보여주기; (3) 공유 지갑 — 지갑 B 가 두 번째 계정에 연결될 때 코드는 선택해야 합니다: 거절, 다중 허용, 동의 하의 이전. 각 선택이 테스트가 달린 정책 표의 한 줄이 됩니다.

무엇을 증명하나

계정 연결은 편의 기능처럼 보이지만 실제로는 권한 시스템입니다: 모든 연결은 부여된 능력이고, 모든 해제는 취소이며, 그 사이의 타이밍 규칙이 계정 탈취 표면입니다. 체인은 무허가 키 그래프를 줄 뿐 — 사람이 무엇인지는 제품이 명시적으로 결정해야 합니다.

← 전체 개발 노트 · 워크스페이스 인덱스 · 맨 위 ↑