Skip to content

[🧠 Smart Account] EIP-7702 network toggle & TX confirmation UI#1910

Merged
piatoss3612 merged 10 commits intoroy/keplr-2044from
roy/keplr-2045
Apr 3, 2026
Merged

[🧠 Smart Account] EIP-7702 network toggle & TX confirmation UI#1910
piatoss3612 merged 10 commits intoroy/keplr-2044from
roy/keplr-2045

Conversation

@jungcome7
Copy link
Copy Markdown
Contributor

@jungcome7 jungcome7 commented Apr 1, 2026

#1906에서 만든 백엔드 서비스를 사용자가 실제로 조작할 수 있는 UI 페이지로 만듭니다.

변경사항

ObservableQuery로 delegation 상태 마이그레이션

delegation 상태가 여러 UI에서 반복 참조되어 쿼리 캐시가 필요하므로, 기존 메시지 기반 조회(GetSmartAccountDelegationStatusMsg)를 MobX ObservableQuery로 교체하고 관련 메시지/핸들러/서비스 메서드를 삭제했습니다.

네트워크 목록 페이지

체인별 토글 스위치로 Smart Account를 켜고 끌 수 있으며, 토글 클릭 시 200ms 애니메이션 후 확인 페이지로 이동합니다.

트랜잭션 확인 페이지

Summary, Detail, Fee 카드로 구성되며, 수수료는 discriminated union 상태 머신으로 관리합니다. USD 듀얼 표시, 잔액 부족 경고, 추정 실패 시 재시도를 지원합니다.

라우트 및 진입점 연결

계정 드롭다운에 "EVM Smart Account" 메뉴를 추가하고, /wallet/smart-account/wallet/smart-account/confirm 라우트를 등록합니다.

백엔드 정리

레거시 delegation 메시지/핸들러/init 등록을 삭제하고, ALLOWED_DELEGATORS를 background에서 export하여 stores-eth에서 참조하도록 했습니다.

스크린샷

2026-04-01.10.30.15.mov

코드 구조

apps/extension/src/pages/wallet/smart-account/
├── constants.ts                          # 상수
├── utils.ts                              # truncateAddress, formatFee
├── hooks/
│   ├── use-eip7702-chains.ts             # EIP-7702 지원 체인 필터링
│   └── use-redirect-if-invalid.ts        # 유효하지 않은 접근 시 리다이렉트
├── network-list/
│   ├── network-list.tsx                  # 네트워크 목록 페이지
│   ├── hooks/use-chain-statuses.ts       # ObservableQuery 기반 체인별 상태 + 애니메이션
│   └── components/chain-row-item.tsx     # 체인 이미지 + 이름 + 토글
└── confirm/
    ├── confirm.tsx                       # 트랜잭션 확인 페이지
    ├── hooks/
    │   ├── use-confirm-route.ts          # URL 파싱 + 네비게이션
    │   └── use-smart-account-fee.ts      # 수수료 추정 + USD + 잔액 체크
    └── components/
        ├── card.tsx                      # 공유 Card styled component
        ├── summary-card.tsx              # 아이콘 + 제목 + 설명
        ├── detail-card.tsx               # 계정/현재/전환/Delegator/네트워크
        └── fee-card.tsx                  # 수수료 + 잔액 부족 경고 + 재시도

UI ↔ 백엔드 통신 플로우 — 업그레이드 시나리오

[사용자]                 [UI 팝업]                      [백그라운드]
   │                       │                               │
   │  계정 메뉴 클릭         │                               │
   │──────────────────────>│                               │
   │                       │                               │
   │                       │── ObservableQuery ───────────>│  (MobX 관찰 시 자동)
   │                       │   eth_getCode × 11체인         │
   │                       │<── @computed delegationStatus │
   │                       │                               │
   │  Ethereum 토글 클릭    │                               │
   │──────────────────────>│                               │
   │                       │  (200ms 애니메이션)              │
   │                       │                               │
   │                       │── EstimateSmartAccountFeeMsg >│
   │                       │                               │── fillUnsignedEVMTx
   │                       │                               │   (batch RPC 6개)
   │                       │<── {estimatedFeeWei} ────────│
   │                       │                               │
   │  수수료 확인 ($0.04)    │                               │
   │  [승인] 클릭            │                               │
   │──────────────────────>│                               │
   │                       │── UpgradeSmartAccountMsg ────>│
   │                       │                               │── 검증→서명→전송→폴링
   │                       │<── txHash ───────────────────│
   │                       │                               │
   │  ✅ 성공 토스트          │                               │
   │  목록 복귀 + 토글 전환   │                               │

Test plan

Sepolia testnet 기준:

  • 계정 드롭다운 → EVM Smart Account → 네트워크 목록 → Ethereum 토글 → 확인 페이지 → 승인 → 업그레이드 성공 → 목록 복귀 시 토글 ON 반영
  • 업그레이드된 체인 토글 → 다운그레이드 확인 → 승인 → 성공 → 토글 OFF 반영
  • 잔액 부족 계정에서 확인 페이지 진입 → 경고 표시 + 승인 버튼 비활성화

🤖 Generated with Claude Code

jungcome7 and others added 7 commits April 1, 2026 22:16
…atus

MobX ObservableQuery 기반으로 delegation 상태를 조회합니다.
기존 메시지 기반 조회 대비: 자동 캐시, MobX 관찰 시 자동 fetch, 라이프사이클 관리를 제공합니다.

- ObservableQuerySmartAccountDelegationStatusInner: eth_getCode → @computed parseDelegation
- HasMapStore 래퍼로 주소별 쿼리 인스턴스 자동 관리
- allowedDelegators 옵션을 EthereumQueries에 추가하고 root.tsx에서 ALLOWED_DELEGATORS 전달
- ALLOWED_DELEGATORS를 background/index.ts에서 export

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ObservableQuery로 마이그레이션 완료에 따라 메시지 기반 delegation 상태 조회를 제거합니다.

- GetSmartAccountDelegationStatusMsg 클래스 삭제
- handler.ts에서 해당 case 제거
- init.ts에서 메시지 등록 제거
- service.ts에서 getDelegationStatus 메서드 삭제

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
양 페이지(네트워크 목록, 확인)에서 공유하는 훅과 유틸리티를 추가합니다.

- useEip7702Chains: chainStore에서 eip-7702 feature 플래그 체인 필터링
- useRedirectIfInvalid: 유효하지 않은 접근 시 홈으로 리다이렉트
- utils.ts: truncateAddress, formatFee, DELEGATOR_DISPLAY, 딜레이 상수

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
체인별 Smart Account 토글 목록 페이지를 추가합니다.

- network-list.tsx: 체인 이미지 + 이름 + 토글 스위치, 200ms 애니메이션 후 confirm 이동
- useChainStatuses: ObservableQuery 기반 delegation 상태 조회 + confirm 복귀 시 선택적 애니메이션
- ChainRowItem: 개별 체인 행 컴포넌트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
트랜잭션 확인 페이지와 수수료 추정 훅을 추가합니다.

- confirm.tsx: Summary + Detail + Fee 카드 구성, 더블클릭 방지, 성공/실패 토스트
- useConfirmRoute: URL 파라미터 파싱 + 네비게이션 (라우트 전담)
- useSmartAccountFee: discriminated union 상태 머신, USD 환산, 잔액 부족 체크
- SummaryCard/DetailCard/FeeCard: 프레젠테이셔널 컴포넌트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Smart Account UI를 앱에 연결합니다.

- index.tsx: /wallet/smart-account, /wallet/smart-account/confirm 라우트 등록
- wallet/index.ts: 페이지 컴포넌트 re-export
- account-item.tsx: 계정 드롭다운에 "EVM Smart Account" 메뉴 항목 추가 (eip7702 체인 있을 때만)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- en/ko/zh-cn.json에 smart account 관련 13개 i18n 키 추가
- helper.ts: buildDummyAuthorizationList의 address 파라미터 타입 명확화
- DSTypography: minor fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jungcome7 jungcome7 requested a review from a team as a code owner April 1, 2026 13:19
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
keplr-wallet-extension Ready Ready Preview, Comment Apr 3, 2026 5:55am

Request Review

@jungcome7 jungcome7 temporarily deployed to github-pages-preview April 1, 2026 13:19 — with GitHub Actions Inactive
@jungcome7 jungcome7 changed the title [🎨 Smart Account] EIP-7702 네트워크 토글 + TX 확인 UI [🧠 Smart Account] EIP-7702 네트워크 토글 + TX 확인 UI Apr 1, 2026
@jungcome7 jungcome7 self-assigned this Apr 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 1, 2026

Storybook Deployed

🔗 Preview: https://chainapsis.github.io/keplr-wallet/storybook/

Last updated: 2026-04-03T05:54:42Z

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f719fe907

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const firstChain = eip7702Chains[0];
if (!firstChain) return "";
try {
return accountStore.getAccount(firstChain.chainId).ethereumHexAddress;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Query delegation status for requested vault

This page is keyed by id (vaultId) in the URL, but the delegation lookup uses accountStore.getAccount(...), which is the currently selected wallet rather than the requested vault. If a user opens Smart Account from a non-selected account row, the toggle state and computed upgrade/downgrade direction can reflect a different account and lead to incorrect confirmation flows (for example, immediate "already upgraded"/"not upgraded" failures when submitting for the target vault).

Useful? React with 👍 / 👎.


const hexAddress = useMemo(() => {
try {
return accountStore.getAccount(chainId).ethereumHexAddress;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use vault-scoped address on confirm page

The transaction messages are sent with vaultId, but the displayed/accounted address comes from accountStore.getAccount(chainId), i.e. the globally selected account. For non-selected vaults this shows the wrong address and computes insufficientBalance against another account, so the Approve button can be disabled/enabled based on unrelated funds.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vault id랑 매칭되는 주소를 가져올 수 있는 방법이 필요할 것 같습니다
이건 저도 좀 고민해볼게요

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거는 stores-eth를 확장하기는 너무 복잡해질 것 같고, internal 요청만 허용하는 GetEthereumAddressForVaultMsg같은 이름의 메시지랑 핸들러를 추가해서 계정 정보를 가져와야할 것 같습니다 @jungcome7

-> 지금 문제되는 부분은 활설화된 계정(A)과 다른 계정(B)의 옵션에서 Evm 스마트 계정을 클릭하면, stores-eth account store에서 백그라운드로 요청을 보낼 때 A를 참조하게 돼서 A 계정에서의 스마트 계정 활성화 여부를 가져오게 됩니다

Copy link
Copy Markdown
Contributor Author

@jungcome7 jungcome7 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 그러네요 완전히 놓쳤습니다

Copy link
Copy Markdown
Contributor Author

@jungcome7 jungcome7 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀하신대로 수정했습니다!
d87d8ff


@computed
get delegationStatus(): DelegationStatus {
if (!this.response || !this.response.data) return "ready";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid defaulting unknown delegation state to ready

Returning "ready" when no response exists conflates "empty code" with "query not loaded/failed". On RPC errors (or before first fetch), unsupported/unknown states are shown as upgradeable, which drives users into avoidable failures later in the flow. This should distinguish missing/error responses from actual eth_getCode results before mapping to ready.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 ready를 반환하는 건 문제없어 보이는데 ui에서 쿼리의 loading, error 상태를 같이 체크를 해줘야 될 거 같습니다

Copy link
Copy Markdown
Contributor Author

@jungcome7 jungcome7 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요렇게 수정했습니다

  • ChainStatus에 체인별 isLoading/hasError 추가
  • ChainRowItemdisabled prop 추가하여 로딩/에러 시 토글 비활성화
  • 캐시된 응답이 있으면 refetch 중에도 토글 활성 유지 (깜빡임 방지)

b7efe4831

상수(TOGGLE_ANIMATION_DELAY_MS, STATUS_UPDATE_DELAY_MS, DELEGATOR_DISPLAY)를
constants.ts로 분리하고 utils.ts에는 순수 함수만 남깁니다.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jungcome7 jungcome7 temporarily deployed to github-pages-preview April 2, 2026 03:04 — with GitHub Actions Inactive
@jungcome7 jungcome7 changed the title [🧠 Smart Account] EIP-7702 네트워크 토글 + TX 확인 UI [Smart Account] EIP-7702 network toggle & TX confirmation UI Apr 2, 2026
@jungcome7 jungcome7 changed the title [Smart Account] EIP-7702 network toggle & TX confirmation UI [🧠 Smart Account] EIP-7702 network toggle & TX confirmation UI Apr 2, 2026

@computed
get delegationStatus(): DelegationStatus {
if (!this.response || !this.response.data) return "ready";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 ready를 반환하는 건 문제없어 보이는데 ui에서 쿼리의 loading, error 상태를 같이 체크를 해줘야 될 거 같습니다

new InExtensionMessageRequester()
.sendMessage(
BACKGROUND_PORT,
new EstimateSmartAccountFeeMsg(chainId, vaultId)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시뮬레이션 로직을 stores-eth 쪽에 구현해서 gas simulator랑 같이 쓰지 않고
백그라운드 메시지로 구현하신 이유가 궁급합니다!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dummy authorization tuple로 gas estimation하는 게 원래 안됐던 걸로 기억하는데 되는 것도 신기하네요

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

선택된 계정과 다른 vaultId를 가진 계정에서 실행하는 경우에 대해서는 이렇게 처리하는 게 베스트이긴 하군요


const hexAddress = useMemo(() => {
try {
return accountStore.getAccount(chainId).ethereumHexAddress;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vault id랑 매칭되는 주소를 가져올 수 있는 방법이 필요할 것 같습니다
이건 저도 좀 고민해볼게요

…ounts

Add GetEthereumAddressForVaultMsg to resolve ethereum hex address
for a specific vaultId instead of relying on the globally selected
account. This fixes incorrect address, balance, and delegation
status when managing smart accounts for non-active vaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@piatoss3612 piatoss3612 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 변경사항 먼저 머지하시면
#1909
이 pr에서 충돌 해결하고 핑드릴게요

…or errored

Add per-chain isLoading/hasError to ChainStatus and pass disabled
prop to ChainRowItem toggle, preventing interaction before the
delegation status query resolves.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@piatoss3612
Copy link
Copy Markdown
Member

제가 머지하겠습니다

@piatoss3612 piatoss3612 merged commit a66b7b1 into roy/keplr-2044 Apr 3, 2026
10 checks passed
@piatoss3612
Copy link
Copy Markdown
Member

piatoss3612 commented Apr 3, 2026

아 베이스브랜치 실수;;
해결했습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants