diff --git a/app/css/interceptor.css b/app/css/interceptor.css index f50cf86e..72bb0d72 100644 --- a/app/css/interceptor.css +++ b/app/css/interceptor.css @@ -891,9 +891,9 @@ svg.spinner > circle { .dashed-notification { border-style: dashed; - background: unset; - border-width: medium; - border-color: white; + background: unset; + border-width: medium; + border-color: white; } .popup-footer { diff --git a/app/ts/background/background.ts b/app/ts/background/background.ts index 0b8e8daa..2159be34 100644 --- a/app/ts/background/background.ts +++ b/app/ts/background/background.ts @@ -648,7 +648,7 @@ export async function popupMessageHandler( case 'popup_get_export_settings': return await exportSettings() case 'popup_set_rpc_list': return await setNewRpcList(simulator, parsedRequest, settings) case 'popup_simulateGovernanceContractExecution': return await simulateGovernanceContractExecutionOnPass(simulator.ethereum, parsedRequest) - case 'popup_simulateGnosisSafeTransaction': return await simulateGnosisSafeTransactionOnPass(simulator.ethereum, parsedRequest) + case 'popup_simulateGnosisSafeTransaction': return await simulateGnosisSafeTransactionOnPass(simulator.ethereum, parsedRequest.data.gnosisSafeMessage) case 'popup_changeAddOrModifyAddressWindowState': return await changeAddOrModifyAddressWindowState(simulator.ethereum, parsedRequest) case 'popup_fetchAbiAndNameFromEtherscan': return await popupFetchAbiAndNameFromEtherscan(parsedRequest) case 'popup_openWebPage': return await openWebPage(parsedRequest) diff --git a/app/ts/background/popupMessageHandlers.ts b/app/ts/background/popupMessageHandlers.ts index af0adb2e..5fdc5b31 100644 --- a/app/ts/background/popupMessageHandlers.ts +++ b/app/ts/background/popupMessageHandlers.ts @@ -2,7 +2,7 @@ import { changeActiveAddressAndChainAndResetSimulation, changeActiveRpc, refresh import { getSettings, setUseTabsInsteadOfPopup, setMakeMeRich, setPage, setUseSignersAddressAsActiveAddress, updateWebsiteAccess, exportSettingsAndAddressBook, importSettingsAndAddressBook, getMakeMeRich, getUseTabsInsteadOfPopup, getMetamaskCompatibilityMode, setMetamaskCompatibilityMode, getPage } from './settings.js' import { getPendingTransactionsAndMessages, getCurrentTabId, getTabState, saveCurrentTabId, setRpcList, getRpcList, getPrimaryRpcForChain, getRpcConnectionStatus, updateUserAddressBookEntries, getSimulationResults, setIdsOfOpenedTabs, getIdsOfOpenedTabs, updatePendingTransactionOrMessage, getLatestUnexpectedError, addEnsLabelHash, addEnsNodeHash } from './storageVariables.js' import { Simulator, parseEvents, parseInputData } from '../simulation/simulator.js' -import { ChangeActiveAddress, ChangeMakeMeRich, ChangePage, RemoveTransaction, RequestAccountsFromSigner, TransactionConfirmation, InterceptorAccess, ChangeInterceptorAccess, ChainChangeConfirmation, EnableSimulationMode, ChangeActiveChain, AddOrEditAddressBookEntry, GetAddressBookData, RemoveAddressBookEntry, InterceptorAccessRefresh, InterceptorAccessChangeAddress, Settings, RefreshConfirmTransactionMetadata, ChangeSettings, ImportSettings, SetRpcList, UpdateHomePage, SimulateGovernanceContractExecution, ChangeAddOrModifyAddressWindowState, FetchAbiAndNameFromEtherscan, OpenWebPage, DisableInterceptor, SetEnsNameForHash, UpdateConfirmTransactionDialog, UpdateConfirmTransactionDialogPendingTransactions, SimulateGnosisSafeTransaction, SimulateExecutionReply } from '../types/interceptor-messages.js' +import { ChangeActiveAddress, ChangeMakeMeRich, ChangePage, RemoveTransaction, RequestAccountsFromSigner, TransactionConfirmation, InterceptorAccess, ChangeInterceptorAccess, ChainChangeConfirmation, EnableSimulationMode, ChangeActiveChain, AddOrEditAddressBookEntry, GetAddressBookData, RemoveAddressBookEntry, InterceptorAccessRefresh, InterceptorAccessChangeAddress, Settings, RefreshConfirmTransactionMetadata, ChangeSettings, ImportSettings, SetRpcList, UpdateHomePage, SimulateGovernanceContractExecution, ChangeAddOrModifyAddressWindowState, FetchAbiAndNameFromEtherscan, OpenWebPage, DisableInterceptor, SetEnsNameForHash, UpdateConfirmTransactionDialog, UpdateConfirmTransactionDialogPendingTransactions, SimulateExecutionReply } from '../types/interceptor-messages.js' import { formEthSendTransaction, formSendRawTransaction, resolvePendingTransactionOrMessage, updateConfirmTransactionView } from './windows/confirmTransaction.js' import { getAddressMetadataForAccess, requestAddressChange, resolveInterceptorAccess } from './windows/interceptorAccess.js' import { resolveChainChange } from './windows/changeChain.js' @@ -29,6 +29,7 @@ import { makeSureInterceptorIsNotSleeping } from './sleeping.js' import { craftPersonalSignPopupMessage } from './windows/personalSign.js' import { checkAndThrowRuntimeLastError, updateTabIfExists } from '../utils/requests.js' import { modifyObject } from '../utils/typescript.js' +import { VisualizedPersonalSignRequestSafeTx } from '../types/personal-message-definitions.js' export async function confirmDialog(simulator: Simulator, websiteTabConnections: WebsiteTabConnections, confirmation: TransactionConfirmation) { await resolvePendingTransactionOrMessage(simulator, websiteTabConnections, confirmation) @@ -389,12 +390,12 @@ export async function simulateGovernanceContractExecutionOnPass(ethereum: Ethere })) } -export async function simulateGnosisSafeTransactionOnPass(ethereum: EthereumClientService, request: SimulateGnosisSafeTransaction) { +export async function simulateGnosisSafeTransactionOnPass(ethereum: EthereumClientService, gnosisSafeMessage: VisualizedPersonalSignRequestSafeTx) { const simulationResults = await getSimulationResults() - const gnosisTransactionExecutionVisualisation = await simulateGnosisSafeMetaTransaction(request.data.gnosisSafeMessage, simulationResults.simulationState, ethereum) + const gnosisTransactionExecutionVisualisation = await simulateGnosisSafeMetaTransaction(gnosisSafeMessage, simulationResults.simulationState, ethereum) return await sendPopupMessageToOpenWindows(serialize(SimulateExecutionReply, { method: 'popup_simulateExecutionReply' as const, - data: { ...gnosisTransactionExecutionVisualisation, transactionOrMessageIdentifier: request.data.gnosisSafeMessage.messageIdentifier } + data: { ...gnosisTransactionExecutionVisualisation, transactionOrMessageIdentifier: gnosisSafeMessage.messageIdentifier } })) } diff --git a/app/ts/background/windows/confirmTransaction.ts b/app/ts/background/windows/confirmTransaction.ts index 4565d48b..60e8e654 100644 --- a/app/ts/background/windows/confirmTransaction.ts +++ b/app/ts/background/windows/confirmTransaction.ts @@ -24,6 +24,7 @@ import { craftPersonalSignPopupMessage } from './personalSign.js' import { getSettings } from '../settings.js' import * as funtypes from 'funtypes' import { modifyObject } from '../../utils/typescript.js' +import { simulateGnosisSafeTransactionOnPass } from '../popupMessageHandlers.js' const pendingConfirmationSemaphore = new Semaphore(1) @@ -289,6 +290,9 @@ export async function openConfirmTransactionDialogForMessage( await updateConfirmTransactionView(ethereumClientService) await tryFocusingTabOrWindow(openedDialog) + if (visualizedPersonalSignRequest.type === 'SafeTx') { + await simulateGnosisSafeTransactionOnPass(simulator.ethereum, visualizedPersonalSignRequest) + } }) } catch(e) { await handleUnexpectedError(e) diff --git a/app/ts/components/pages/PersonalSign.tsx b/app/ts/components/pages/PersonalSign.tsx index 4d1739fb..0639d7f5 100644 --- a/app/ts/components/pages/PersonalSign.tsx +++ b/app/ts/components/pages/PersonalSign.tsx @@ -138,11 +138,11 @@ function SignRequest({ visualizedPersonalSignRequest, renameAddressCallBack, edi

{ visualizedPersonalSignRequest.message }

} - case 'SafeTx': return case 'EIP712': { return @@ -192,60 +192,6 @@ function SignRequest({ visualizedPersonalSignRequest, renameAddressCallBack, edi } } -function SafeTx({ visualizedPersonalSignRequestSafeTx, renameAddressCallBack, activeAddress, editEnsNamedHashCallBack }: { visualizedPersonalSignRequestSafeTx: VisualizedPersonalSignRequestSafeTx, renameAddressCallBack: RenameAddressCallBack, activeAddress: bigint, editEnsNamedHashCallBack: EditEnsNamedHashCallBack }) { - return <> - - - { visualizedPersonalSignRequestSafeTx.message.domain.chainId !== undefined - ? <> - - - - : <> - } - - - - - { visualizedPersonalSignRequestSafeTx.message.message.gasToken !== 0n - ? <> - - }/> - - : <> - } - - - - - { visualizedPersonalSignRequestSafeTx.message.message.refundReceiver !== 0n ? - <> - - }/> - - : <> - } - - - - }/> - - }/> - -

Gnosis Safe meta transaction input:

-
-

{ dataStringWith0xStart(visualizedPersonalSignRequestSafeTx.message.message.data) }

-
-

Parsed Gnosis Safe meta transaction:

- { visualizedPersonalSignRequestSafeTx.parsedMessageData?.type !== 'Parsed' ?

No ABI available

: } - -} - type EIP712Table = { enrichedEIP712Message: EnrichedEIP712Message renameAddressCallBack: RenameAddressCallBack @@ -334,11 +280,66 @@ type ExtraDetailsCardParams = { renameAddressCallBack: RenameAddressCallBack } + +type GnosisSafeExtraDetailsParams = { + visualizedPersonalSignRequestSafeTx: VisualizedPersonalSignRequestSafeTx + renameAddressCallBack: RenameAddressCallBack +} + +function GnosisSafeExtraDetails({ visualizedPersonalSignRequestSafeTx, renameAddressCallBack }: GnosisSafeExtraDetailsParams) { + return <> + + { visualizedPersonalSignRequestSafeTx.message.domain.chainId !== undefined + ? <> + + + + : <> + } + + + + + { visualizedPersonalSignRequestSafeTx.message.message.gasToken !== 0n + ? <> + + }/> + + : <> + } + + + + + { visualizedPersonalSignRequestSafeTx.message.message.refundReceiver !== 0n ? + <> + + }/> + + : <> + } + + + + }/> + + }/> + +

Gnosis Safe meta transaction input:

+
+

{ dataStringWith0xStart(visualizedPersonalSignRequestSafeTx.message.message.data) }

+
+

Parsed Gnosis Safe meta transaction:

+ { visualizedPersonalSignRequestSafeTx.parsedMessageData?.type !== 'Parsed' ?

No ABI available

: } + +} + function ExtraDetails({ visualizedPersonalSignRequest, renameAddressCallBack }: ExtraDetailsCardParams) { const [showSummary, setShowSummary] = useState(false) if (visualizedPersonalSignRequest.type !== 'Permit2' && visualizedPersonalSignRequest.type !== 'Permit' - && visualizedPersonalSignRequest.type !== 'OrderComponents') { + && visualizedPersonalSignRequest.type !== 'OrderComponents' + && visualizedPersonalSignRequest.type !== 'SafeTx') { return <> } @@ -361,6 +362,7 @@ function ExtraDetails({ visualizedPersonalSignRequest, renameAddressCallBack }: { visualizedPersonalSignRequest.type !== 'Permit' ? <> : } { visualizedPersonalSignRequest.type !== 'OrderComponents' ? <> : } + { visualizedPersonalSignRequest.type !== 'SafeTx' ? <> : } diff --git a/app/ts/components/simulationExplaining/customExplainers/GnosisSafeVisualizer.tsx b/app/ts/components/simulationExplaining/customExplainers/GnosisSafeVisualizer.tsx index c34779b0..56cade1c 100644 --- a/app/ts/components/simulationExplaining/customExplainers/GnosisSafeVisualizer.tsx +++ b/app/ts/components/simulationExplaining/customExplainers/GnosisSafeVisualizer.tsx @@ -3,6 +3,7 @@ import { MessageToPopup, SimulateExecutionReply } from '../../../types/intercept import { VisualizedPersonalSignRequestSafeTx } from '../../../types/personal-message-definitions.js' import { RenameAddressCallBack, RpcConnectionStatus } from '../../../types/user-interface-types.js' import { ErrorComponent } from '../../subcomponents/Error.js' +import { SmallAddress } from '../../subcomponents/address.js' import { EditEnsNamedHashCallBack } from '../../subcomponents/ens.js' import { Transaction } from '../Transactions.js' import { useEffect, useState } from 'preact/hooks' @@ -19,7 +20,6 @@ type ShowSuccessOrFailureParams = { const requestToSimulate = (gnosisSafeMessage: VisualizedPersonalSignRequestSafeTx) => sendPopupMessageToBackgroundPage({ method: 'popup_simulateGnosisSafeTransaction', data: { gnosisSafeMessage } }) - const ShowSuccessOrFailure = ({ simulateExecutionReply, activeAddress, renameAddressCallBack, editEnsNamedHashCallBack, gnosisSafeMessage }: ShowSuccessOrFailureParams) => { if (simulateExecutionReply === undefined) { return
@@ -103,20 +103,16 @@ export function GnosisSafeVisualizer(param: GnosisSafeVisualizerParams) { }, [param.activeAddress, param.gnosisSafeMessage.messageIdentifier]) if (activeAddress === undefined) return <> - return <> -
- -
-

Simulation of this transaction should the multisig approve the transaction:

-
-
- { simulateExecutionReply === undefined ? <> : - - } -
+ return <> +
+ +

Approves Gnosis Safe

+
+

message

-
+
+ Outcome of the message, should the multisig approve it -
+ + { simulateExecutionReply === undefined ? <> : +
+ +
+ } } diff --git a/package-lock.json b/package-lock.json index c0355348..84e259de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "@noble/curves": "0.8.0", "@noble/hashes": "1.4.0", "@preact/signals": "1.1.3", - "ethers": "6.11.0", + "ethers": "6.13.1", "funtypes": "5.1.0", "preact": "10.8.1", "webextension-polyfill": "0.10.0" @@ -106,9 +106,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/ethers": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.0.tgz", - "integrity": "sha512-kPHNTnhVWiWU6AVo6CAeTjXEK24SpCXyZvwG9ROFjT0Vlux0EOhWKBAeC+45iDj80QNJTYaT1SDEmeunT0vDNw==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.1.tgz", + "integrity": "sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A==", "funding": [ { "type": "individual", @@ -126,7 +126,7 @@ "@types/node": "18.15.13", "aes-js": "4.0.0-beta.5", "tslib": "2.4.0", - "ws": "8.5.0" + "ws": "8.17.1" }, "engines": { "node": ">=14.0.0" @@ -191,15 +191,15 @@ "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { diff --git a/package.json b/package.json index 04dc9d63..c1a977a7 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@noble/curves": "0.8.0", "@noble/hashes": "1.4.0", "@preact/signals": "1.1.3", - "ethers": "6.11.0", + "ethers": "6.13.1", "funtypes": "5.1.0", "preact": "10.8.1", "webextension-polyfill": "0.10.0"