Skip to content

[🧠 Smart Account] Batch sign UI + upgrade/downgrade fee editing#1915

Open
jungcome7 wants to merge 10 commits intoroy/evm-smart-accountfrom
roy/keplr-2029
Open

[🧠 Smart Account] Batch sign UI + upgrade/downgrade fee editing#1915
jungcome7 wants to merge 10 commits intoroy/evm-smart-accountfrom
roy/keplr-2029

Conversation

@jungcome7
Copy link
Copy Markdown
Collaborator

@jungcome7 jungcome7 commented Apr 7, 2026

요약

KEPLR-2028에서 준비한 인프라(TX 조립, 가스 시뮬레이션)를 UI에 연결하고, 업/다운그레이드에 수수료 편집을 추가합니다.

배치 서명 UI 파일 구조:

views/sign-batch-view/
├── sign-batch-view.tsx           # 메인 뷰 (interaction lifecycle + approve/reject)
├── hooks/
│   └── use-batch-transaction.ts  # TX 조립 + signingData 관리
├── batch-summary-card.tsx        # 배치 아이콘 + 트랜잭션 수
├── batch-detail-card.tsx         # 계정, 요청자, 네트워크
├── calls-list.tsx                # 접이식 트랜잭션 리스트 (intent 매핑 + 4byte fallback)
├── upgrade-notice.tsx            # EOA → 스마트 어카운트 알림
└── advanced-details.tsx          # Nonce + raw TX data

변경사항

배치 서명 UI

  • dApp의 wallet_sendCalls 요청 시 EthSignType.EIP5792를 감지하여 배치 서명 페이지를 표시합니다.
  • sign-tx-view와 동일한 fee hooks를 사용하여 수수료 편집(low/average/high/custom)을 지원합니다.
  • useBatchTransaction 훅이 atomic batch TX 조립과 signingData 관리를 담당합니다.
  • 각 call의 메서드명은 intent 매핑(15 selector → 5 카테고리) + 4byte.directory fallback으로 표시합니다.

수수료 편집 통합

  • 업/다운그레이드의 읽기전용 수수료 표시(useSmartAccountFee + FeeCard)를 편집 가능한 useFeeConfig + FeeControl로 교체했습니다. useSmartAccountFeeFeeCard는 삭제됩니다.
  • UpgradeSmartAccountMsgSmartAccountFeeParams를 추가하여 UI에서 선택한 수수료가 sendEip7702Tx로 전달됩니다.

보안

  • signEthereumBatch callback에서 delegator 주소를 ALLOWED_DELEGATORS와 대조하는 validateAuthorizationList 검증이 누락되어 있어 추가했습니다.
  • authorization nonce를 UI 값 대신 background에서 txNonce + 1로 강제 설정하여 조작을 방지합니다.

스크린샷

스크린샷 2026-04-07 오후 4 15 13

테스트

🤖 Generated with Claude Code

@jungcome7 jungcome7 requested a review from a team as a code owner April 7, 2026 07:15
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 7, 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 8, 2026 8:16am

Request Review

@jungcome7 jungcome7 changed the base branch from roy/evm-smart-account to roy/keplr-2028 April 7, 2026 07:20
@jungcome7 jungcome7 changed the base branch from roy/keplr-2028 to roy/evm-smart-account April 7, 2026 07:20
@jungcome7 jungcome7 self-assigned this Apr 7, 2026
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: fdb4b50d7a

ℹ️ 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".

Comment on lines +32 to +34
status === "ready"
? buildDummyAuthorizationList(ALLOWED_DELEGATORS[0], evmChainId)
: undefined;
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 Align batch auth nonce with the selected tx nonce

When status === "ready", this builds authorizationList from buildDummyAuthorizationList(...), which hardcodes nonce 0x1, while the transaction nonce is taken from request.nonce. In KeyRingEthereumService.signEthereumBatch, the new validation requires auth.nonce === tx.nonce + 1 before signing, so any account with nonce > 0 will fail approval for wallet_sendCalls even though the UI flow looks valid. Derive the dummy auth nonce from request.nonce + 1 when constructing signing data.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

f8b322aae에서 해결. nonce 검증을 제거하고 background에서 txNonce + 1로 강제 설정합니다.

size: "large",
isLoading,
disabled: approveDisabled,
disabled: isLoading || gasConfig.gas <= 0,
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 Block smart-account submit when fee state is invalid

The confirm button is now enabled whenever gasConfig.gas > 0, but this refactor removed the previous guards for failed/unfinished fee estimation and insufficient balance. That allows upgrade/downgrade submission in invalid fee states, leading to predictable broadcast failures and generic transaction errors instead of preventing submission up front. This should be gated by fee/tx validation state (as in other transaction-signing flows), not only gas being positive.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

b060a2acb에서 반영. useTxConfigsValidate로 교체하여 fee 에러, 잔액 부족, 로딩 상태에서 approve 버튼을 비활성화합니다. EIP-1559 fee 12초 갱신도 추가.

jungcome7 and others added 6 commits April 7, 2026 18:49
Add the batch sign view for wallet_sendCalls approval flow with:
- Summary card showing batch icon and transaction count
- Detail card with account, requester, and network info
- Expandable calls list with 4-byte method name decoding
- Upgrade notice for non-delegated (EOA) accounts
- Advanced details section with nonce and raw TX data
- FeeControl for gas fee editing (same hooks as sign-tx-view)
- OP Stack L1 data fee support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…downgrade

Switch from read-only fee display to editable FeeControl (same as sign-tx-view):
- Replace useSmartAccountFee + FeeCard with useFeeConfig + useGasSimulator + FeeControl
- Add OP Stack L1 data fee support via simulateOpStackL1Fee
- Unify IconCircle size (2.5rem) with batch summary card
- Remove unused i18n fee keys and formatFee utility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ng security

Upgrade/downgrade feeParams:
- Add optional SmartAccountFeeParams to UpgradeSmartAccountMsg/DowngradeSmartAccountMsg
- sendEip7702Tx uses UI-provided fee when feeParams present, fetches nonce only
- Add feeParams validation in validateBasic (gasLimit required, fee strategy required)

Batch signing security:
- Add validateAuthorizationList in signEthereumBatch callback (was missing)
- Enforce auth nonce = txNonce + 1 for self-sponsoring pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The signEthereumBatch callback was validating auth.nonce against txNonce+1,
but the UI sends a dummy nonce ("0x1") from buildDummyAuthorizationList.
Instead of validating, the background now enforces authNonce = txNonce + 1
directly, matching the sendEip7702Tx pattern (self-sponsoring).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace gasConfig.gas <= 0 with useTxConfigsValidate to properly block
the approve button on fee errors, insufficient balance, and loading
states. Applied to both batch sign view and upgrade/downgrade confirm.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… names

KNOWN_SELECTORS의 메소드명(Transfer, Approve 등 15개)을 하드코딩된 영문에서
i18n 키로 변경하여 한국어/중국어 번역을 지원합니다.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…+ 4byte fallback

Replace 15 hardcoded Solidity function name translations with a 2-tier approach:

Tier 1 - Intent mapping: 15 selectors → 5 intent categories (transfer,
approve, swap, deposit, withdraw). All swap variants (V2/V3/Universal
Router) unified under single "Swap" label instead of confusing
translations like "정확한 토큰 스왑" or "단일 정확 입력".

Tier 2 - 4byte.directory fallback: For unknown selectors, reuse the
existing queriesStore.simpleQuery.queryGet pattern from execute-contract.tsx
to fetch function names dynamically. Results are cached by MobX query
infrastructure automatically.

- 15 method-name i18n keys → 5 intent keys (×3 languages = 45→15 strings)
- CallCard wrapped with observer for reactive 4byte query
- Add index number to labels ("Swap #1") for batch context clarity
- Remove "(Wrap)"/"(Unwrap)" suffixes to avoid deposit()/withdraw() collision

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jungcome7 added a commit that referenced this pull request Apr 8, 2026
…llet PR #1915)

15 KNOWN_SELECTORS → 5 intent categories + index labels ("Swap #1")

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

@codex review

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: 0b3368b5e4

ℹ️ 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".

Comment on lines +35 to +37
const tx = createAtomicBatchTransaction(
request.calls,
hexAddress,
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 Guard batch assembly against contract-deploy calls

wallet_sendCalls requests can legally omit call.to (contract deployment), but this hook always calls createAtomicBatchTransaction during render; that helper throws when any call has no to. Because there is no local guard/fallback, a valid deployment-style batch request crashes the approval view instead of being rejected in a controlled way, so users cannot safely respond to that interaction.

Useful? React with 👍 / 👎.

Comment on lines +144 to +147
const l1Fee = await ethereumAccount.simulateOpStackL1Fee({
to: hexAddress,
value: "0x0",
data: "0x",
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 Estimate OP L1 fee from the real batch transaction

On OP Stack chains, simulateOpStackL1Fee is called with an empty self-transfer payload (to=self, data=0x) instead of the actual batch calldata. For batched calls this materially underestimates L1 data fee, which can suppress insufficient-balance errors and let users approve a transaction that later fails at broadcast/execution because total fee requirements are higher than shown.

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.

이 부분은 인코딩된 콜데이터를 넣어주셔야 되겠네요.
l1 fee 계산은 그냥 콜데이터 크기에 비례해 얼마 정도 나온다 추산하는 정도라 시뮬레이션이 성공하든 안하든 상관없이 항상 값이 보장됩니다.

jungcome7 and others added 2 commits April 8, 2026 16:58
… and copy to batch calls

- Decode ERC-20 approve/transfer/transferFrom calldata to show spender, recipient, and formatted token amount
- Query token contract info (symbol, decimals) and display human-readable amounts via CoinPretty
- Detect unlimited approvals (threshold 10^15 after decimals) and show warning badge
- Convert native value from wei to chain currency (e.g., ETH)
- Add full calldata view toggle and clipboard copy for addresses and data
- Add i18n keys for decoded fields (ko, en, zh-cn)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract calls-list/ folder with single-responsibility files
- constants.ts: SELECTOR_INTENT, ABI selectors, types
- utils.ts: getSelector, toTitleCase, tryDecodeErc20, truncateAddress
- call-card.tsx: main card component with collapse
- decoded-info.tsx: ERC-20 decoded approve/transfer display
- call-data-row.tsx: data preview with expand/copy
- hooks/use-decoded-call.ts: token decoding + unlimited detection
- hooks/use-method-name.ts: intent + 4byte resolution
- hooks/use-native-value.ts: wei → native currency conversion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show "클립보드에 복사됨" toast on successful copy via useNotification
- Remove redundant local copied state from call-data-row
- Add i18n key for copy notification (ko, en, zh-cn)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feeParams.maxPriorityFeePerGas = `0x${BigInt(
maxPriorityFeePerGas.truncate().toString()
).toString(16)}`;
} else if (gasPrice) {
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.

7702 tx의 경우에는 gas price 필드를 사용하지 않아서 eip1559 dynamic fee 필드를 사용해야만 합니다.

문제는 bnb smart chain이 gas price를 사용하는 legacy 체인인데 불구하고 7702 tx type을 지원하게 되니 필드 미스매치가 발생해서 트랜잭션 실행이 실패하게 되는 것으로 보입니다.

이 경우는 제가 보기에는 어쩔 수 없이 forceDisableLegacyMode 같은 파라미터로 dynamic fee 필드를 강제하도록 할 수 밖에 없을 것 같아요.

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.

batch ui에서도 업그레이드가 수반되어야 하는 경우(7702 tx 실행)에는 forceDisableLegacyMode를 걸어줘야할 거 같습니다.

feeConfig.setL1DataFee(new Dec(BigInt(l1Fee)));
}
})();
}, [chainInfo, chainId, chainStore, ethereumAccount, feeConfig, hexAddress]);
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.

저번 Pr에서 제가 누락한 것 같은데, 이쯤에 refreshEIP1559TxFees interval을 추가해주면 좋을 것 같습니다.

chainId: string,
vaultId: string
vaultId: string,
feeParams?: {
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.

여기에 SmartAccountFeeParams 타입 사용하시면 될 거 같아요.
아래에 반복되는 부분에도

Comment on lines +144 to +147
const l1Fee = await ethereumAccount.simulateOpStackL1Fee({
to: hexAddress,
value: "0x0",
data: "0x",
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.

이 부분은 인코딩된 콜데이터를 넣어주셔야 되겠네요.
l1 fee 계산은 그냥 콜데이터 크기에 비례해 얼마 정도 나온다 추산하는 정도라 시뮬레이션이 성공하든 안하든 상관없이 항상 값이 보장됩니다.

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