한 번 연결한다는 것은 세션을 인가한다는 뜻이다
WalletConnect 연결은 단순한 주소 교환이 아닙니다. namespace, 체인, 메서드, 계정, 만료, 갱신 이벤트가 애플리케이션이 추적해야 할 상시 권한을 기술합니다.
WalletConnect Sign client(또는 Reown AppKit)로 최소 권한 제안과 넓은 권한 제안을 하나씩 만들고, 계정 변경, 체인 변경, 세션 갱신, 만료, 릴레이 단절, 재연결, 명시적 해지를 차례로 실행합니다 — 각 이벤트가 애플리케이션 상태를 올바르게 좁히거나 무효화하는지 확인합니다.
기술 노트
각 항목이 실제로 무엇을 보여주고 어떻게 동작하는지 — 위 카드보다 자세한 기술 설명입니다.
목적: UI 는 보통 세션 상태를 "connected" 하나로 뭉갭니다. 그러면 어떤 메서드가 아직 인가되어 있는지가 가려지고, 지갑이 애플리케이션 바깥에서 상태를 바꿀 때 낡은 계정 버그가 생깁니다. WalletConnect 세션에는 계정, 체인, 메서드, 이벤트, 만료가 들어 있습니다. 이것을 `isConnected` 불리언 하나로 다루면, 애플리케이션이 무엇을 요청할 수 있는지와 캐시된 계정이 아직 최신인지 알려 주는 정보가 사라집니다.
동작 방식: 가장 작은 메서드 집합으로 연결하고 넓은 기본 제안과 비교한 뒤, 계정 변경, 체인 변경, 세션 갱신, 만료, 릴레이 단절, 명시적 해지를 차례로 실행합니다. ### PoC WalletConnect Sign client 또는 Reown AppKit 으로 최소 권한 제안과 넓은 권한 제안을 각각 만듭니다. 계정·체인 변경, 세션 갱신, 만료, 릴레이 단절, 재연결, 명시적 연결 해제를 실행합니다. 각 이벤트가 애플리케이션 상태를 올바르게 무효화하거나 좁히는지 확인합니다. ### 무엇을 증명하나 연결 UX 는 권한 관리입니다. 안전한 기본값은 최소한의 namespace 와 메서드 집합, 관찰 가능한 세션 상태 머신, 눈에 보이는 해지 경로입니다 — 낡은 상태에서도 살아남는 초록색 점이 아닙니다. 참고: [Reown WalletConnect 세션 사용법](https://docs.reown.com/advanced/api/sign/dapp-usage).
검토 후 보완: ### 같은 병, 다른 장기 — 생애주기에서 인가로 제목이 곧 재정의입니다 — **한 번 연결 = 세션을 인가하는 것이지 주소를 교환하는 게 아니다.** 세션은 *상시 권한* — 범위 + 수명 + 변경 이벤트 — 이고, 불리언 `isConnected` 는 그걸 거의 다 버리는 손실 있는 투영입니다. `a-boolean-hides-a-state-machine` 이 이름 붙인 패턴의 인가 쪽 멤버입니다. ### 초록 점은 세 개의 독립 계층을 뭉갠다 `private-rpc-visibility`·`bundler-paymaster-dependencies` 의 바로 그 구조적 오류가 지갑에 나타난 것입니다: | 계층 | 진짜 질문 | 초록 점의 위장 | | --- | --- | --- | | **릴레이/전송** | 지금 지갑과 *대화*할 수 있나? | "연결됨" | | **세션/인가** | 그 권한이 아직 *유효*한가(만료·취소 아님)? | "연결됨" | | **계정/상태** | 캐시된 계정·체인이 아직 *최신*인가? | "연결됨" | 릴레이 끊김은 세션을 무효화하지 **않고**, 재연결이 재인가하지 **않습니다.** 전송 가용성은 인가가 아닙니다 — `bundler-paymaster-dependencies` 가 "accepted ≠ settled" 로 그은 그 선. ### 보안의 핵심은 최소권한 세션은 `namespaces`·`chains`·`methods`·`accounts`(EIP-155 / CAIP-2 / CAIP-10)를 지정합니다. 광범위한 기본 — 모든 체인, 모든 메서드, `eth_sign` 포함 — 을 요청하는 것은 OAuth 의 "이 앱이 전부에 접근하려 함" 안티패턴의 web3 판입니다. **메서드 집합이 곧 공격 표면**입니다 — `eth_sign`(블라인드 서명)을 인가한 세션은 `personal_sign` 으로 좁힌 세션보다 범주적으로 큰 부채입니다. 그래서 안전한 기본값은 *가장 작은* 네임스페이스·메서드 집합이고, 최소 대 광범위 제안 비교가 그 차이를 가정이 아니라 *측정 가능*하게 만듭니다. `embedded-wallet-policy`·`agentic-intent-veto` 와 같은 "실제로 무엇을 인가했나" 질문, 전송 표준 한 층 아래. ### 스테일 계정이 구체적이고 위험한 버그 지갑은 **앱 밖에서** 상태를 바꿀 수 있습니다 — 사용자가 계정 전환, 체인 전환, 세션 만료, 취소. UI 가 초록 점 뒤에 캐시된 계정을 쥐고 있으면 *틀린* 계정·체인의 잔고를 보여주거나 서명을 요청합니다. `accountsChanged`/`chainChanged`/`session_update`/`session_delete`/`session_expire` 이벤트는 바로 앱 상태를 좁히거나 무효화하려 존재하고, 이를 무시하는 것이 **곧** 스테일 상태를 살아남는 초록 점입니다. 한 당사자의 캐시 뷰가 그라운드 트루스가 아니라는 `rpc-view-not-consensus` 의 교훈을, 당신 자신의 세션 캐시에 적용한 것. ### 불변식: 모든 이벤트는 좁히거나 무효화하지, 조용히 넓히지 않는다 "각 이벤트가 앱 상태를 올바르게 좁히거나 무효화하는지 단언"이 실제로 인코딩하는 게 이것입니다. 권한은 오직 *줄어들거나* 새 승인을 요구해야지, 조용히 *늘어나면* 안 됩니다. 명시적 재제안 없이 메서드나 계정을 얻은 듯 보이는 세션은 버그 — 또는 공격입니다. 세션을 명시적 상태기계(제안됨 → 성립됨 → 갱신됨 → 만료/끊김/취소됨 → 재제안)로 모델링하는 것이 그 불변식을 검사 가능하게 합니다. ### 만료와 취소는 1급 개념이지 예외가 아니다 `expiry` 지난 세션은 권한이 아닙니다 — 연결됨으로 취급하는 것은 `receipt-is-not-settlement` 의 인가판 쌍둥이(*완료처럼 보이지만* 유효하지 않음)입니다. 그리고 취소는 **보이고 양방향**이어야 합니다 — 사용자는 지갑에서 `session_delete` 할 수 있고, 앱도 자체 취소 경로를 드러내야 합니다. 깨끗이 관찰·취소할 수 없는 "연결됨"은 남아 있는 권한 — 잊힌 OAuth 승인 실패 유형이며, 인가 도메인의 `who-holds-the-mint` / "누가 멈추나" 주제입니다.