Skip to content

Commit

Permalink
Merge branch 'main' into manifest-update
Browse files Browse the repository at this point in the history
  • Loading branch information
KillariDev authored Jun 21, 2024
2 parents 378ef4d + fa736d1 commit 55bb772
Show file tree
Hide file tree
Showing 35 changed files with 1,032 additions and 747 deletions.
67 changes: 63 additions & 4 deletions app/css/interceptor.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
@charset "utf-8";

@font-face {
font-family: "Atkinson";
src: url("../fonts/Atkinson-Hyperlegible-Regular-102a.woff2") format("woff2");
font-weight: normal;
font-style: normal;
}

@font-face {
font-family: "Inter";
src: url("../fonts/Inter-VariableFont.ttf") format("ttf");
}

html { font-size: 100%; }
body { font-family: "Inter" }

:root {
--bg-color: #303030;
Expand Down Expand Up @@ -41,14 +54,15 @@ html { font-size: 100%; }
}

button:where(:not(.btn)) {
font-family: "Inter";
background-color: var(--primary-color);
}

button:where(:not(.btn)):hover {
background-color: var(--highlighted-primary-color);
}

button:not(.btn):disabled, button[disabled]) {
button:not(.btn):disabled, button:not(.btn)[disabled] {
background-color: var(--disabled-primary-color);
border-color: transparent;
}
Expand Down Expand Up @@ -248,6 +262,7 @@ li {
}

.card-header {
column-gap: 1rem;
background-color: var(--card-header-bg-color);
}

Expand Down Expand Up @@ -328,23 +343,56 @@ li {
flex-direction: column;
}

.button.is-reveal:after {
content: '';
border-style: solid;
border-width: 2px 2px 0 0;
display: inline-block;
height: 0.6em;
width: 0.6em;
position: relative;
top: 6%;
transform: rotate(135deg);
transform-origin: 66% 33%;
transition: transform 150ms;
flex-shrink: 0;
}

.dropdown.is-active > .dropdown-trigger > button:after {
transform: rotate(-45deg);
}

.dropdown-trigger > button.is-danger:before {
content: '!';
width: 1.1em;
height: 1.1em;
font-size: 0.9em;
background: white;
color: var(--negative-color);
flex: 0 0 auto;
align-items: center;
display: flex;
justify-content: center;
border-radius: 100%;
}

.dropdown-content {
background-color: var(--card-content-bg-color);
box-shadow: 0px 8px 16px 0px rgb(0 0 0 / 20%);
}

.dropdown-item {
color: var(--text-color);
background: transparent;
border: initial;
cursor: pointer;
}

a.dropdown-item.is-active, button.dropdown-item.is-active {
background-color: var(--primary-color);
}

.card-header-icon {
padding: 0;
padding-left: 0.75rem;
padding-right: 0.75rem;
background-color: transparent;
}

Expand Down Expand Up @@ -1106,3 +1154,14 @@ summary:where(details[open] > *) {
place-content: center;
justify-items: center;
}

.text-legible {
font-family: 'Atkinson';
}

.truncate {
display: block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
Binary file not shown.
Binary file added app/fonts/Inter-VariableFont.ttf
Binary file not shown.
7 changes: 0 additions & 7 deletions app/img/warning-sign-white.svg

This file was deleted.

53 changes: 45 additions & 8 deletions app/ts/background/background.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { InpageScriptRequest, PopupMessage, RPCReply, Settings } from '../types/interceptor-messages.js'
import { InpageScriptRequest, PopupMessage, RPCReply, Settings, SimulateExecutionReplyData } from '../types/interceptor-messages.js'
import 'webextension-polyfill'
import { Simulator, parseEvents, parseInputData, runProtectorsForTransaction } from '../simulation/simulator.js'
import { getSimulationResults, getTabState, setLatestUnexpectedError, updateSimulationResults, updateSimulationResultsWithCallBack } from './storageVariables.js'
import { changeSimulationMode, getSettings, getMakeMeRich, getWethForChainId } from './settings.js'
import { blockNumber, call, chainId, estimateGas, gasPrice, getAccounts, getBalance, getBlockByNumber, getCode, getLogs, getPermissions, getSimulationStack, getTransactionByHash, getTransactionCount, getTransactionReceipt, netVersion, personalSign, sendTransaction, subscribe, switchEthereumChain, unsubscribe, web3ClientVersion, getBlockByHash, feeHistory, installNewFilter, uninstallNewFilter, getFilterChanges, getFilterLogs, handleIterceptorError } from './simulationModeHanders.js'
import { changeActiveAddress, changeMakeMeRich, changePage, confirmDialog, refreshSimulation, removeTransactionOrSignedMessage, requestAccountsFromSigner, refreshPopupConfirmTransactionSimulation, confirmRequestAccess, changeInterceptorAccess, changeChainDialog, popupChangeActiveRpc, enableSimulationMode, addOrModifyAddressBookEntry, getAddressBookData, removeAddressBookEntry, refreshHomeData, interceptorAccessChangeAddressOrRefresh, refreshPopupConfirmTransactionMetadata, changeSettings, importSettings, exportSettings, setNewRpcList, simulateGovernanceContractExecutionOnPass, openNewTab, settingsOpened, changeAddOrModifyAddressWindowState, popupFetchAbiAndNameFromEtherscan, openWebPage, disableInterceptor, requestNewHomeData, setEnsNameForHash } from './popupMessageHandlers.js'
import { CompleteVisualizedSimulation, EnrichedEthereumEvents, EnrichedEthereumInputData, ProtectorResults, SimulationState, VisualizedSimulatorState, WebsiteCreatedEthereumUnsignedTransactionOrFailed } from '../types/visualizer-types.js'
import { changeActiveAddress, changeMakeMeRich, changePage, confirmDialog, refreshSimulation, removeTransactionOrSignedMessage, requestAccountsFromSigner, refreshPopupConfirmTransactionSimulation, confirmRequestAccess, changeInterceptorAccess, changeChainDialog, popupChangeActiveRpc, enableSimulationMode, addOrModifyAddressBookEntry, getAddressBookData, removeAddressBookEntry, refreshHomeData, interceptorAccessChangeAddressOrRefresh, refreshPopupConfirmTransactionMetadata, changeSettings, importSettings, exportSettings, setNewRpcList, simulateGovernanceContractExecutionOnPass, openNewTab, settingsOpened, changeAddOrModifyAddressWindowState, popupFetchAbiAndNameFromEtherscan, openWebPage, disableInterceptor, requestNewHomeData, setEnsNameForHash, simulateGnosisSafeTransactionOnPass } from './popupMessageHandlers.js'
import { CompleteVisualizedSimulation, ProtectorResults, SimulationState, VisualizedSimulatorState, WebsiteCreatedEthereumUnsignedTransaction, WebsiteCreatedEthereumUnsignedTransactionOrFailed } from '../types/visualizer-types.js'
import { WebsiteTabConnections } from '../types/user-interface-types.js'
import { askForSignerAccountsFromSignerIfNotAvailable, interceptorAccessMetadataRefresh, requestAccessFromUser, updateInterceptorAccessViewWithPendingRequests } from './windows/interceptorAccess.js'
import { FourByteExplanations, METAMASK_ERROR_FAILED_TO_PARSE_REQUEST, METAMASK_ERROR_NOT_AUTHORIZED, METAMASK_ERROR_NOT_CONNECTED_TO_CHAIN, ERROR_INTERCEPTOR_DISABLED, NEW_BLOCK_ABORT, ETHEREUM_LOGS_LOGGER_ADDRESS } from '../utils/constants.js'
import { sendActiveAccountChangeToApprovedWebsitePorts, sendMessageToApprovedWebsitePorts, updateWebsiteApprovalAccesses, verifyAccess } from './accessManagement.js'
import { getActiveAddressEntry, getAddressBookEntriesForVisualiser, identifyAddress, nameTokenIds, retrieveEnsLabelHashes, retrieveEnsNodeHashes } from './metadataUtils.js'
import { getActiveAddress, sendPopupMessageToOpenWindows } from './backgroundUtils.js'
import { assertNever, assertUnreachable, modifyObject } from '../utils/typescript.js'
import { DistributiveOmit, assertNever, assertUnreachable, modifyObject } from '../utils/typescript.js'
import { EthereumClientService } from '../simulation/services/EthereumClientService.js'
import { appendTransaction, calculateGasPrice, copySimulationState, getEmptySimulationStateWithRichAddress, getNonceFixedSimulatedTransactions, getTokenBalancesAfter, getWebsiteCreatedEthereumUnsignedTransactions, mockSignTransaction, setSimulationTransactionsAndSignedMessages } from '../simulation/services/SimulationModeEthereumClientService.js'
import { appendTransaction, calculateGasPrice, copySimulationState, getEmptySimulationStateWithRichAddress, getNonceFixedSimulatedTransactions, getTokenBalancesAfter, getWebsiteCreatedEthereumUnsignedTransactions, mockSignTransaction, setSimulationTransactionsAndSignedMessages, simulateEstimateGas } from '../simulation/services/SimulationModeEthereumClientService.js'
import { Semaphore } from '../utils/semaphore.js'
import { JsonRpcResponseError, handleUnexpectedError, isFailedToFetchError, isNewBlockAbort } from '../utils/errors.js'
import { formSimulatedAndVisualizedTransaction } from '../components/formVisualizerResults.js'
Expand All @@ -38,6 +38,8 @@ import { connectedToSigner, ethAccountsReply, signerChainChanged, signerReply, w
import { makeSureInterceptorIsNotSleeping } from './sleeping.js'
import { decodeEthereumError } from '../utils/errorDecoding.js'
import { estimateEthereumPricesForTokens } from '../simulation/priceEstimator.js'
import { EnrichedEthereumEvents, EnrichedEthereumInputData } from '../types/EnrichedEthereumData.js'
import { VisualizedPersonalSignRequestSafeTx } from '../types/personal-message-definitions.js'

async function updateMetadataForSimulation(simulationState: SimulationState, ethereum: EthereumClientService, requestAbortController: AbortController | undefined, eventsForEachTransaction: readonly EnrichedEthereumEvents[], inputData: readonly EnrichedEthereumInputData[], protectorResults: readonly ProtectorResults[]) {
const settingsPromise = getSettings()
Expand All @@ -59,8 +61,8 @@ async function updateMetadataForSimulation(simulationState: SimulationState, eth
}
}

export const simulateGovernanceContractExecution = async (pendingTransaction: PendingTransaction, ethereum: EthereumClientService) => {
const returnError = (text: string) => ({ success: false as const, error: { type: 'Other' as const, message: text } })
export const simulateGovernanceContractExecution = async (pendingTransaction: PendingTransaction, ethereum: EthereumClientService): Promise<DistributiveOmit<SimulateExecutionReplyData, 'transactionOrMessageIdentifier'>> => {
const returnError = (errorMessage: string) => ({ success: false as const, errorType: 'Other' as const, errorMessage })
try {
// identifies compound governane call and performs simulation if the vote passes
if (pendingTransaction.transactionOrMessageCreationStatus !== 'Simulated') return returnError('Still simulating the voting transaction')
Expand All @@ -84,7 +86,7 @@ export const simulateGovernanceContractExecution = async (pendingTransaction: Pe
if (pendingTransaction.transactionToSimulate.transaction.to === null) return returnError('The transaction creates a contract instead of casting a vote')
const params = governanceContractInterface.decodeFunctionData(voteFunction, dataStringWith0xStart(pendingTransaction.transactionToSimulate.transaction.input))
const addr = await identifyAddress(ethereum, undefined, pendingTransaction.transactionToSimulate.transaction.to)
if (!('abi' in addr) || addr.abi === undefined) return { success: false as const, error: { type: 'MissingAbi' as const, message: 'ABi for the governance contract is missing', addressBookEntry: addr } }
if (!('abi' in addr) || addr.abi === undefined) return { success: false as const, errorType: 'MissingAbi' as const, errorMessage: 'ABi for the governance contract is missing', errorAddressBookEntry: addr }
const contractExecutionResult = await simulateCompoundGovernanceExecution(ethereum, addr, params[0])
if (contractExecutionResult === undefined) return returnError('Failed to simulate governance execution')
const parentBlock = await ethereum.getBlock(undefined)
Expand Down Expand Up @@ -121,6 +123,40 @@ export const simulateGovernanceContractExecution = async (pendingTransaction: Pe
}
}

export const simulateGnosisSafeMetaTransaction = async (gnosisSafeMessage: VisualizedPersonalSignRequestSafeTx, simulationState: SimulationState | undefined, ethereumClientService: EthereumClientService): Promise<DistributiveOmit<SimulateExecutionReplyData, 'transactionOrMessageIdentifier'>> => {
const returnError = (errorMessage: string) => ({ success: false as const, errorType: 'Other' as const, errorMessage })
try {
const transactionWithoutGas = {
value: gnosisSafeMessage.message.message.value,
to: gnosisSafeMessage.to.address,
maxPriorityFeePerGas: 0n,
maxFeePerGas: 0n,
input: gnosisSafeMessage.parsedMessageData.input,
type: '1559' as const,
from: gnosisSafeMessage.verifyingContract.address,
nonce: 0n,
chainId: ethereumClientService.getChainId(),
}
const gasLimit = gnosisSafeMessage.message.message.baseGas !== 0n ? { gas: gnosisSafeMessage.message.message.baseGas } : await simulateEstimateGas(ethereumClientService, undefined, simulationState, transactionWithoutGas)
if ('error' in gasLimit) return returnError(gasLimit.error.message)
const transaction = { ...transactionWithoutGas, gas: gasLimit.gas }
const metaTransaction: WebsiteCreatedEthereumUnsignedTransaction = {
website: gnosisSafeMessage.website,
created: new Date(),
originalRequestParameters: { method: 'eth_sendTransaction', params: [transaction] },
transactionIdentifier: gnosisSafeMessage.messageIdentifier,
success: true,
transaction,
}
const simulationStateAfterGnosisSafeMetaTransaction = await appendTransaction(ethereumClientService, undefined, simulationState, metaTransaction)
return { success: true as const, result: await visualizeSimulatorState(simulationStateAfterGnosisSafeMetaTransaction, ethereumClientService, undefined) }
} catch(error) {
console.warn(error)
if (error instanceof Error) return returnError(error.message)
return returnError('Unknown error occured')
}
}

async function visualizeSimulatorState(simulationState: SimulationState, ethereum: EthereumClientService, requestAbortController: AbortController | undefined): Promise<VisualizedSimulatorState> {
const transactions = getWebsiteCreatedEthereumUnsignedTransactions(simulationState.simulatedTransactions)
const eventsForEachTransactionPromise = Promise.all(simulationState.simulatedTransactions.map(async (simulatedTransaction) => simulatedTransaction.ethSimulateV1CallResult.status === 'failure' ? [] : await parseEvents(simulatedTransaction.ethSimulateV1CallResult.logs, ethereum, requestAbortController)))
Expand Down Expand Up @@ -612,6 +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_changeAddOrModifyAddressWindowState': return await changeAddOrModifyAddressWindowState(simulator.ethereum, parsedRequest)
case 'popup_fetchAbiAndNameFromEtherscan': return await popupFetchAbiAndNameFromEtherscan(parsedRequest)
case 'popup_openWebPage': return await openWebPage(parsedRequest)
Expand Down
13 changes: 9 additions & 4 deletions app/ts/background/metadataUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { addressString, addressStringWithout0x, bytesToUnsigned, checksummedAddress } from '../utils/bigint.js'
import { AddressBookEntries, AddressBookEntry } from '../types/addressBookTypes.js'
import { EnrichedEthereumEventWithMetadata, EnrichedEthereumEvents, EnrichedEthereumInputData, EnsEvent, NamedTokenId, SimulationState, TokenEvent, TokenVisualizerResultWithMetadata } from '../types/visualizer-types.js'
import { NamedTokenId, SimulationState } from '../types/visualizer-types.js'
import { tokenMetadata, contractMetadata, erc721Metadata, erc1155Metadata } from '@darkflorist/address-metadata'
import { ethers } from 'ethers'
import { ENS_ADDR_REVERSE_NODE, ENS_TOKEN_WRAPPER, ETHEREUM_COIN_ICON, ETHEREUM_LOGS_LOGGER_ADDRESS, MOCK_ADDRESS } from '../utils/constants.js'
Expand All @@ -16,6 +16,7 @@ import { EthereumBytes32 } from '../types/wire-types.js'
import { ENSNameHashes } from '../types/ens.js'
import { keccak_256 } from '@noble/hashes/sha3'
const LOGO_URI_PREFIX = '../vendor/@darkflorist/address-metadata'
import { EnrichedEthereumEventWithMetadata, EnrichedEthereumEvents, EnrichedEthereumInputData, EnsEvent, SolidityVariable, TokenEvent, TokenVisualizerResultWithMetadata } from '../types/EnrichedEthereumData.js'

const pathJoin = (parts: string[], sep = '/') => parts.join(sep).replace(new RegExp(sep + '{1,}', 'g'), sep)

Expand Down Expand Up @@ -157,13 +158,17 @@ export async function identifyAddress(ethereumClientService: EthereumClientServi
return entry
}

export async function getAddressBookEntriesForVisualiser(ethereumClientService: EthereumClientService, requestAbortController: AbortController | undefined, events: EnrichedEthereumEvents, inputData: readonly EnrichedEthereumInputData[], simulationState: SimulationState): Promise<AddressBookEntry[]> {
const eventAndTransactionArguments = [...events.flatMap((event) => event.type !== 'NonParsed' ? event.args : []), ...inputData.flatMap((event) => event.type !== 'NonParsed' ? event.args : [])]
const addressesInEventsAndInputData = eventAndTransactionArguments.flatMap((argumentVariable) => {
export const getAddressesForSolidityTypes = (variables: readonly SolidityVariable[]) => {
return variables.map((argumentVariable) => {
if (argumentVariable.typeValue.type === 'address') return argumentVariable.typeValue.value
if (argumentVariable.typeValue.type === 'address[]') return argumentVariable.typeValue.value
return undefined
}).filter((address): address is bigint => address !== undefined)
}

export async function getAddressBookEntriesForVisualiser(ethereumClientService: EthereumClientService, requestAbortController: AbortController | undefined, events: EnrichedEthereumEvents, inputData: readonly EnrichedEthereumInputData[], simulationState: SimulationState): Promise<AddressBookEntry[]> {
const eventAndTransactionArguments = [...events.flatMap((event) => event.type !== 'NonParsed' ? event.args : []), ...inputData.flatMap((event) => event.type !== 'NonParsed' ? event.args : [])]
const addressesInEventsAndInputData = getAddressesForSolidityTypes(eventAndTransactionArguments)
const addressesToFetchMetadata = [...addressesInEventsAndInputData, ...events.map((event) => event.address)]

for (const tx of simulationState.simulatedTransactions) {
Expand Down
Loading

0 comments on commit 55bb772

Please sign in to comment.