feat: multi-tx simulation and batch-specific approval UI#2238
feat: multi-tx simulation and batch-specific approval UI#2238janek26 wants to merge 1 commit into03-06-refactor_transaction_requests_arrayfrom
Conversation
8c2e0cb to
a3fd029
Compare
f0bd569 to
8e02de6
Compare
a3fd029 to
6a6b56c
Compare
0d7df2b to
f0b92c6
Compare
6a6b56c to
965fcd9
Compare
f0b92c6 to
732e6f9
Compare
965fcd9 to
876ac3f
Compare
732e6f9 to
bc92150
Compare
8b637e8 to
eebd2fe
Compare
bc92150 to
59e9783
Compare
59e9783 to
2d4b17c
Compare
36350be to
ded1927
Compare
2d4b17c to
74d097a
Compare
ded1927 to
d642d91
Compare
7a22023 to
e52798a
Compare
367d8f9 to
f4c61ee
Compare
11e308f to
94da91a
Compare
40ad160 to
c50cdc9
Compare
94da91a to
be04e5e
Compare
c50cdc9 to
6de788e
Compare
be04e5e to
1e8abe4
Compare
c24b094 to
fd93362
Compare
4fd1d89 to
a8c4375
Compare
fd93362 to
ba3adba
Compare
a8c4375 to
d95fc80
Compare
7d0004d to
e6c04f9
Compare
d95fc80 to
b7dd5d6
Compare
e6c04f9 to
e945d1e
Compare
81f7e84 to
44353f6
Compare
e945d1e to
806e379
Compare
DanielSinclair
left a comment
There was a problem hiding this comment.
Mentioned a few issues that I think we'll need to fix or further investigate before merging. I assume you'd be able to do that today. We'd want QA to run through those edge case scenarios as well.
| maxHeight: 200, | ||
| overflow: 'auto', | ||
| wordBreak: 'break-word', | ||
| }} |
There was a problem hiding this comment.
Drifting away from the design system primitives here. When mocking this or fixing a layout issue, would point Codex at the design-system/ library and ask it to critique and itterate based on the design system constraints
| queryFn: async () => { | ||
| const normalized = transactions.map((t) => ({ | ||
| ...t, | ||
| to: t.to || '', |
There was a problem hiding this comment.
Spooked by fallback here too
| to: tx.to?.toString() ?? '', | ||
| value: tx.value?.toString() ?? '0', | ||
| data: tx.data?.toString() ?? '0x', | ||
| })) ?? [], |
There was a problem hiding this comment.
Same issue from the prior PR
| }); | ||
|
|
||
| if (!results[0]) throw 'UNSUPPORTED'; | ||
| if (results.length === 0) throw 'UNSUPPORTED'; |
There was a problem hiding this comment.
Do we filter out these potential null values elsewhere?
| onRejectRequest={onRejectRequest} | ||
| loading={loading} | ||
| dappStatus={dappMetadata?.status} | ||
| dappStatus={effectiveDappStatus} |
There was a problem hiding this comment.
Do we have a loading state here, or do we always flash scam state?
| }); | ||
| const effectiveDappStatus = | ||
| simulationResult.data?.scanning.result !== 'OK' | ||
| ? DAppStatus.Scam |
There was a problem hiding this comment.
We're losing the separate Warning state handling
There was a problem hiding this comment.
This also maps WARNING scans to DAppStatus.Scam, even though the metadata API distinguishes warning- level results from malicious ones. For transactions that are risky but not malicious, the approval UI still switches to the red scam affordance and “send anyway” behavior, which overstates the scan result and changes the normal approval flow.
|
|
||
| const [expanded, setExpanded] = useState(false); | ||
|
|
||
| const isScamDapp = dappMetadata?.status === DAppStatus.Scam; |
There was a problem hiding this comment.
I think these states are going out of sync.
The parent component (index.tsx) computes effectiveDappStatus which incorporates simulation scanning results, and passes it to SendTransactionActions. But SendTransactionInfo never receives
effectiveDappStatus — it computes isScamDapp independently from raw dappMetadata?.status only.This means if simulation flags a transaction as malicious but the backend dapp metadata says the dapp
is OK:
- The approve button correctly shows "Send Transaction Anyway" (via effectiveDappStatus)
- But the header still says "Transaction request" instead of "Dangerous request" (via isScamDapp)
- The DappHostName component also uses the raw status, not the effective one
The scam UI is split across two components with two different data sources.
| transactionSpeedClicked: | ||
| event.dappPromptSendTransactionSpeedClicked, | ||
| }} | ||
| chainId={getChainIdForRequest(request, activeSession?.chainId)} |
There was a problem hiding this comment.
Are we handling edge cases where session chainId differs from the batch request? Assume that might get caught at the provider, but code flow review caught this (havent investigated myself):
When a dapp session is connected on one chain and submits a batch for another, the sheet can approve a batch that has no gas on the target network or block one that actually does, because fee estimation and balance validation are now reading different chains.
806e379 to
7a0d8c3
Compare
44353f6 to
06aeae1
Compare
06aeae1 to
60fa6f8
Compare
7a0d8c3 to
2f7a66d
Compare
60fa6f8 to
5bb953f
Compare
2f7a66d to
ae2abd0
Compare
…ound execution (#2254) This PR aims to replace these 3 from the stack #2236 #2237 #2238 All of them had one common issue pointed out by Daniel in the review, I tried to generalise the sendTransaction interface into working with transaction request arrays, and transform normal sendTransaction requests into a transaction request array of length one. This resulted in multiple issues: 1. transaction requests through sendTransaction and sendCalls with calls length of one would simulate the same 2. If not delegated yet, the delegation would not be simulated, and results would not be verified 3. Serial gas estimation does not represent actual gas costs 1. `est(call1)+est(call2)+est(call3) !== est(call1+call2+call3)` This PR aims to use what's in place instead of forcing everything into a new array format. Instead we're reusing the existing format of having a single transaction request. That"s possible by wrapping calls with `prepareBatchedTransaction` from the delegation sdk. <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces support for the `wallet_sendCalls` method, enhancing batch transaction capabilities. It includes new schemas, hooks, and UI components for better handling of batch requests and transactions, improving error handling and user feedback. ### Detailed summary - Added support for `wallet_sendCalls` in `ApproveAppRequest.tsx`. - Introduced `executeSendCallsBatch` handler and contract. - Created schemas for batch call parameters and execution. - Updated gas estimation logic to accommodate batch transactions. - Enhanced UI components to display batch transaction details and simulation results. - Improved error handling and user notifications for batch requests. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->

Multi-tx simulation and batch-specific approval UI
The approval screen now simulates all calls in a batch together, merges the results, and displays per-call details. Single-transaction approvals are unaffected.
What changed
useSimulateTransactions– ReplacesuseSimulateTransaction. Accepts an array of transactions, simulates them via the backend's batch API, and merges results withmergeSimulations(worst scanning result wins, in/out/approvals concatenated, metas collected per-call).CallDetailscomponent – Extracted fromTransactionDetails. Renders contract info, function name, source code status, and creation date for a single call.TransactionDetailsnow iteratesmetas[]and renders oneCallDetailsper call with a "Call N" label for batches.BatchTransactionData– Data tab for batches: shows each call's target address and calldata separately with a combined copy button.effectiveDappStatusis derived from the simulation scanning result. If simulation flags the request as malicious, the approval screen shows the scam warning regardless of the dapp's metadata status.Simulation.tsx–wrap={false}andflexShrink/minWidthfixes prevent asset amounts from wrapping awkwardly on narrow viewports.Design choices & review focus
meta→metas[]– The simulation response has a singlemetaper transaction. For batches we collect them into an array so the UI can render per-call details. TheTransactionSimulationtype is updated throughout.mergeSimulationspicks the most severe scanning result across all calls. If any call is flagged malicious, the whole batch is treated as malicious. This is conservative by design.SimulationQueryResulttype – A new exported type that bundlesdata,status,error, andisRefetching. This replaces passing four separate props through the component tree.PR-Codex overview
This PR focuses on enhancing the
Alertcomponent's styling and improving the simulation transaction handling across multiple components, including better organization of transaction data and improved error handling.Detailed summary
Alertcomponent to restrict max height and manage overflow.Simulationhandling to merge multiple results and added error management.SendTransactionto use multiple transactions and improved simulation state handling.SendTransactionInfoto include simulation results.