diff --git a/app/ts/background/background.ts b/app/ts/background/background.ts index 9d73b03f..72059cd5 100644 --- a/app/ts/background/background.ts +++ b/app/ts/background/background.ts @@ -4,7 +4,7 @@ import { Simulator, parseEvents, parseInputData, runProtectorsForTransaction } f import { getSimulationResults, getTabState, getTransactionStack, promoteRpcAsPrimary, setLatestUnexpectedError, updateSimulationResults, updateSimulationResultsWithCallBack, updateTransactionStack } from './storageVariables.js' import { changeSimulationMode, getSettings, 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, simulateGnosisSafeTransactionOnPass, retrieveWebsiteAccess, blockOrAllowExternalRequests, removeWebsiteAccess, allowOrPreventAddressAccessForWebsite, removeWebsiteAddressAccess, forceSetGasLimitForTransaction } from './popupMessageHandlers.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, popupfetchAbiAndNameFromBlockExplorer, openWebPage, disableInterceptor, requestNewHomeData, setEnsNameForHash, simulateGnosisSafeTransactionOnPass, retrieveWebsiteAccess, blockOrAllowExternalRequests, removeWebsiteAccess, allowOrPreventAddressAccessForWebsite, removeWebsiteAddressAccess, forceSetGasLimitForTransaction } from './popupMessageHandlers.js' import { CompleteVisualizedSimulation, 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' @@ -720,7 +720,7 @@ export async function popupMessageHandler( case 'popup_simulateGovernanceContractExecution': return await simulateGovernanceContractExecutionOnPass(simulator.ethereum, simulator.tokenPriceService, parsedRequest) case 'popup_simulateGnosisSafeTransaction': return await simulateGnosisSafeTransactionOnPass(simulator.ethereum, simulator.tokenPriceService, parsedRequest.data.gnosisSafeMessage) case 'popup_changeAddOrModifyAddressWindowState': return await changeAddOrModifyAddressWindowState(simulator.ethereum, parsedRequest) - case 'popup_fetchAbiAndNameFromEtherscan': return await popupFetchAbiAndNameFromEtherscan(parsedRequest) + case 'popup_fetchAbiAndNameFromBlockExplorer': return await popupfetchAbiAndNameFromBlockExplorer(parsedRequest) case 'popup_openWebPage': return await openWebPage(parsedRequest) case 'popup_setDisableInterceptor': return await disableInterceptor(simulator, websiteTabConnections, parsedRequest) case 'popup_clearUnexpectedError': return await setLatestUnexpectedError(undefined) diff --git a/app/ts/background/popupMessageHandlers.ts b/app/ts/background/popupMessageHandlers.ts index ce258cf1..522bd007 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, updateTransactionStack } 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, ChangeSettings, ImportSettings, SetRpcList, UpdateHomePage, SimulateGovernanceContractExecution, ChangeAddOrModifyAddressWindowState, FetchAbiAndNameFromEtherscan, OpenWebPage, DisableInterceptor, SetEnsNameForHash, UpdateConfirmTransactionDialog, UpdateConfirmTransactionDialogPendingTransactions, SimulateExecutionReply, BlockOrAllowExternalRequests, RemoveWebsiteAccess, AllowOrPreventAddressAccessForWebsite, RemoveWebsiteAddressAccess, ForceSetGasLimitForTransaction } from '../types/interceptor-messages.js' +import { ChangeActiveAddress, ChangeMakeMeRich, ChangePage, RemoveTransaction, RequestAccountsFromSigner, TransactionConfirmation, InterceptorAccess, ChangeInterceptorAccess, ChainChangeConfirmation, EnableSimulationMode, ChangeActiveChain, AddOrEditAddressBookEntry, GetAddressBookData, RemoveAddressBookEntry, InterceptorAccessRefresh, InterceptorAccessChangeAddress, Settings, ChangeSettings, ImportSettings, SetRpcList, UpdateHomePage, SimulateGovernanceContractExecution, ChangeAddOrModifyAddressWindowState, FetchAbiAndNameFromBlockExplorer, OpenWebPage, DisableInterceptor, SetEnsNameForHash, UpdateConfirmTransactionDialog, UpdateConfirmTransactionDialogPendingTransactions, SimulateExecutionReply, BlockOrAllowExternalRequests, RemoveWebsiteAccess, AllowOrPreventAddressAccessForWebsite, RemoveWebsiteAddressAccess, ForceSetGasLimitForTransaction } from '../types/interceptor-messages.js' import { formEthSendTransaction, formSendRawTransaction, resolvePendingTransactionOrMessage, updateConfirmTransactionView, setGasLimitForTransaction } from './windows/confirmTransaction.js' import { getAddressMetadataForAccess, requestAddressChange, resolveInterceptorAccess } from './windows/interceptorAccess.js' import { resolveChainChange } from './windows/changeChain.js' @@ -18,7 +18,7 @@ import { ExportedSettings } from '../types/exportedSettingsTypes.js' import { isJSON } from '../utils/json.js' import { IncompleteAddressBookEntry } from '../types/addressBookTypes.js' import { EthereumAddress, serialize } from '../types/wire-types.js' -import { fetchAbiFromEtherscan, isValidAbi } from '../simulation/services/EtherScanAbiFetcher.js' +import { fetchAbiFromBlockExplorer, isValidAbi } from '../simulation/services/EtherScanAbiFetcher.js' import { stringToAddress } from '../utils/bigint.js' import { ethers } from 'ethers' import { getIssueWithAddressString } from '../components/ui-utils.js' @@ -522,11 +522,11 @@ export async function changeAddOrModifyAddressWindowState(ethereum: EthereumClie }) } -export async function popupFetchAbiAndNameFromEtherscan(parsedRequest: FetchAbiAndNameFromEtherscan) { - const etherscanReply = await fetchAbiFromEtherscan(parsedRequest.data.address) +export async function popupfetchAbiAndNameFromBlockExplorer(parsedRequest: FetchAbiAndNameFromBlockExplorer) { + const etherscanReply = await fetchAbiFromBlockExplorer(parsedRequest.data.address, parsedRequest.data.chainId) if (etherscanReply.success) { return await sendPopupMessageToOpenWindows({ - method: 'popup_fetchAbiAndNameFromEtherscanReply' as const, + method: 'popup_fetchAbiAndNameFromBlockExplorerReply' as const, data: { windowStateId: parsedRequest.data.windowStateId, success: true, @@ -537,7 +537,7 @@ export async function popupFetchAbiAndNameFromEtherscan(parsedRequest: FetchAbiA }) } return await sendPopupMessageToOpenWindows({ - method: 'popup_fetchAbiAndNameFromEtherscanReply' as const, + method: 'popup_fetchAbiAndNameFromBlockExplorerReply' as const, data: { windowStateId: parsedRequest.data.windowStateId, success: false, diff --git a/app/ts/background/settings.ts b/app/ts/background/settings.ts index 023ef519..770f095e 100644 --- a/app/ts/background/settings.ts +++ b/app/ts/background/settings.ts @@ -4,7 +4,7 @@ import { Settings } from '../types/interceptor-messages.js' import { Semaphore } from '../utils/semaphore.js' import { EthereumAddress } from '../types/wire-types.js' import { WebsiteAccessArray } from '../types/websiteAccessTypes.js' -import { RpcNetwork } from '../types/rpc.js' +import { BlockExplorer, RpcNetwork } from '../types/rpc.js' import { browserStorageLocalGet, browserStorageLocalSafeParseGet, browserStorageLocalSet } from '../utils/storageUtils.js' import { getUserAddressBookEntries, updateUserAddressBookEntries } from './storageVariables.js' import { getUniqueItemsByProperties } from '../utils/typed-arrays.js' @@ -91,6 +91,19 @@ const wethForChainId = new Map([ ['42161', 0x82af49447d8a07e3bd95bd0d56f35241523fbab1n], // Arbitrum ]) +const defaultBlockExplorer = new Map([ + ['1', { apiUrl: 'https://api.etherscan.io/api', apiKey: 'PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8' } ], + ['17000', { apiUrl: 'https://api-holesky.etherscan.io/api', apiKey: 'PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8' }], + ['11155111', { apiUrl: 'https://api-sepolia.etherscan.io/api', apiKey: 'PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8' }], + ['10', { apiUrl: 'https://api-optimistic.etherscan.io/api', apiKey: '4E726IGJ2FAU4IDHZ1TJF5HA9JZ1YKRFK9' }], + ['420', { apiUrl: 'https://api-goerli-optimistic.etherscan.io/api', apiKey: '4E726IGJ2FAU4IDHZ1TJF5HA9JZ1YKRFK9' }], + ['8453', { apiUrl: 'https://api.basescan.org/api', apiKey: 'HHH4UCPI43IYIJGP9MV16Q5REIRSDTAACA' }], + ['84532', { apiUrl: 'https://api-sepolia.basescan.org/api', apiKey: 'HHH4UCPI43IYIJGP9MV16Q5REIRSDTAACA' }], + ['42161', { apiUrl: 'https://api.arbiscan.io/api', apiKey: 'DDP8M43XJYSRBMB8RJGTJ2CW3M8K73CIY6' }], +]) + +export const getDefaultBlockExplorer = (chainId: bigint): BlockExplorer | undefined => defaultBlockExplorer.get(chainId.toString()) + export const getWethForChainId = (chainId: bigint) => wethForChainId.get(chainId.toString()) export async function getSettings() : Promise { diff --git a/app/ts/components/pages/AddNewAddress.tsx b/app/ts/components/pages/AddNewAddress.tsx index fe819155..159f0fdc 100644 --- a/app/ts/components/pages/AddNewAddress.tsx +++ b/app/ts/components/pages/AddNewAddress.tsx @@ -8,7 +8,7 @@ import { AddressIcon } from '../subcomponents/address.js' import { assertUnreachable, modifyObject } from '../../utils/typescript.js' import { ComponentChildren, createRef } from 'preact' import { AddressBookEntry, DeclarativeNetRequestBlockMode, IncompleteAddressBookEntry } from '../../types/addressBookTypes.js' -import { isValidAbi } from '../../simulation/services/EtherScanAbiFetcher.js' +import { isBlockExplorerAvailableForChain, isValidAbi } from '../../simulation/services/EtherScanAbiFetcher.js' import { ModifyAddressWindowState } from '../../types/visualizer-types.js' import { MessageToPopup } from '../../types/interceptor-messages.js' import { XMarkIcon } from '../subcomponents/icons.js' @@ -90,7 +90,7 @@ type RenderinCompleteAddressBookParams = { setUseAsActiveAddress: (useAsActiveAddress: boolean) => void setDeclarativeNetRequestBlockMode: (declarativeNetRequestBlockMode: DeclarativeNetRequestBlockMode) => void setAbi: (abi: string) => void - fetchAbiAndNameFromEtherscan: () => Promise + fetchAbiAndNameFromBlockExplorer: () => Promise setChain: (chainEntry: ChainEntry) => void } @@ -121,7 +121,7 @@ function AbiInput({ abiInput, setAbiInput, disabled }: AbiInputParams) { /> } -function RenderIncompleteAddressBookEntry({ rpcEntries, incompleteAddressBookEntry, setName, setAddress, setSymbol, setAskForAddressAccess, setAbi, canFetchFromEtherScan, fetchAbiAndNameFromEtherscan, setUseAsActiveAddress, setDeclarativeNetRequestBlockMode, setChain }: RenderinCompleteAddressBookParams) { +function RenderIncompleteAddressBookEntry({ rpcEntries, incompleteAddressBookEntry, setName, setAddress, setSymbol, setAskForAddressAccess, setAbi, canFetchFromEtherScan, fetchAbiAndNameFromBlockExplorer, setUseAsActiveAddress, setDeclarativeNetRequestBlockMode, setChain }: RenderinCompleteAddressBookParams) { const Text = (param: { text: ComponentChildren }) => { return

{ param.text } @@ -131,6 +131,7 @@ function RenderIncompleteAddressBookEntry({ rpcEntries, incompleteAddressBookEnt const disableDueToSource = incompleteAddressBookEntry.value.entrySource === 'DarkFloristMetadata' || incompleteAddressBookEntry.value.entrySource === 'Interceptor' const logoUri = incompleteAddressBookEntry.value.addingAddress === false && 'logoUri' in incompleteAddressBookEntry ? incompleteAddressBookEntry.value.logoUri : undefined const selectedChainId = useComputed(() => incompleteAddressBookEntry.value?.chainId || 1n) + const blockExplorerAvailable = useComputed(() => isBlockExplorerAvailableForChain(selectedChainId.value, rpcEntries.value)) return

@@ -158,7 +159,7 @@ function RenderIncompleteAddressBookEntry({ rpcEntries, incompleteAddressBookEnt
- + }/>
@@ -188,7 +189,7 @@ export function AddNewAddress(param: AddAddressParam) { const maybeParsed = MessageToPopup.safeParse(msg) if (!maybeParsed.success) return // not a message we are interested in const parsed = maybeParsed.value - if (parsed.method === 'popup_fetchAbiAndNameFromEtherscanReply') { + if (parsed.method === 'popup_fetchAbiAndNameFromBlockExplorerReply') { setCanFetchFromEtherScan(true) if (param.modifyAddressWindowState.value === undefined || parsed.data.windowStateId !== param.modifyAddressWindowState.value.windowStateId) return if (!parsed.data.success) { @@ -350,13 +351,14 @@ export function AddNewAddress(param: AddAddressParam) { if (previous === undefined) return modifyState(modifyObject(previous, { incompleteAddressBookEntry: modifyObject(previous.incompleteAddressBookEntry, { askForAddressAccess }) })) } - async function fetchAbiAndNameFromEtherscan() { + async function fetchAbiAndNameFromBlockExplorer() { const address = stringToAddress(param.modifyAddressWindowState.value?.incompleteAddressBookEntry.address) if (address === undefined || param.modifyAddressWindowState.value === undefined) return setCanFetchFromEtherScan(false) - await sendPopupMessageToBackgroundPage({ method: 'popup_fetchAbiAndNameFromEtherscan', data: { + await sendPopupMessageToBackgroundPage({ method: 'popup_fetchAbiAndNameFromBlockExplorer', data: { address, windowStateId: param.modifyAddressWindowState.value.windowStateId, + chainId: param.modifyAddressWindowState.value.incompleteAddressBookEntry.chainId } }) } @@ -417,7 +419,7 @@ export function AddNewAddress(param: AddAddressParam) { setDeclarativeNetRequestBlockMode = { setDeclarativeNetRequestBlockMode } setAskForAddressAccess = { setAskForAddressAccess } canFetchFromEtherScan = { canFetchFromEtherScan } - fetchAbiAndNameFromEtherscan = { fetchAbiAndNameFromEtherscan } + fetchAbiAndNameFromBlockExplorer = { fetchAbiAndNameFromBlockExplorer } />
diff --git a/app/ts/simulation/services/EtherScanAbiFetcher.ts b/app/ts/simulation/services/EtherScanAbiFetcher.ts index a59b4452..44ab2fef 100644 --- a/app/ts/simulation/services/EtherScanAbiFetcher.ts +++ b/app/ts/simulation/services/EtherScanAbiFetcher.ts @@ -2,8 +2,10 @@ import { ethers } from 'ethers' import { EtherscanGetABIResult, EtherscanSourceCodeResult } from '../../types/etherscan.js' import { EthereumAddress } from '../../types/wire-types.js' import { addressString, checksummedAddress } from '../../utils/bigint.js' - -const EtherscanABIKey = 'PSW8C433Q667DVEX5BCRMGNAH9FSGFZ7Q8' +import { getDefaultBlockExplorer } from '../../background/settings.js' +import { ChainIdWithUniversal } from '../../types/addressBookTypes.js' +import { RpcEntries } from '../../types/rpc.js' +import { getRpcList } from '../../background/storageVariables.js' async function fetchJson(url: string): Promise<{ success: true, result: unknown } | { success: false, error: string }> { const response = await fetch(url) @@ -20,20 +22,32 @@ export function isValidAbi(abi: string) { } } -export async function fetchAbiFromEtherscan(contractAddress: EthereumAddress) { - const json = await fetchJson(`https://api.etherscan.io/api?module=contract&action=getsourcecode&address=${ addressString(contractAddress) }&apiKey=${ EtherscanABIKey }`) +export function getBlockExplorer(chainId: ChainIdWithUniversal, rpcEntries: RpcEntries) { + if (chainId === 'AllChains') return undefined + const primaryRpc = rpcEntries.find((rpc) => rpc.chainId === chainId && rpc.primary) + if (primaryRpc !== undefined && primaryRpc.blockExplorer !== undefined) return primaryRpc.blockExplorer + return getDefaultBlockExplorer(chainId) +} + +export const isBlockExplorerAvailableForChain = (chainId: ChainIdWithUniversal, rpcEntries: RpcEntries) => getBlockExplorer(chainId, rpcEntries) !== undefined + +export async function fetchAbiFromBlockExplorer(contractAddress: EthereumAddress, chainId: ChainIdWithUniversal) { + const api = getBlockExplorer(chainId, await getRpcList()) + if (api === undefined) return { success: false as const, error: `No block explorer available for chain id: ${ chainId }` } + + const json = await fetchJson(`${ api.apiUrl }?module=contract&action=getsourcecode&address=${ addressString(contractAddress) }&apiKey=${ api.apiKey }`) if (!json.success) return json const parsedSourceCode = EtherscanSourceCodeResult.safeParse(json.result) // Extract ABI from getSourceCode request if not proxy, otherwise attempt to fetch ABI of implementation if (parsedSourceCode.success === false || parsedSourceCode.value.status !== 'success') return { success: false as const, error: 'Failed to parse Etherscan results.'} - + if (parsedSourceCode.value.result[0].Proxy === 'yes' && parsedSourceCode.value.result[0].Implementation !== '') { - const implReq = await fetchJson(`https://api.etherscan.io/api?module=contract&action=getabi&address=${ addressString(parsedSourceCode.value.result[0].Implementation) }&apiKey=${ EtherscanABIKey }`) + const implReq = await fetchJson(`${ api.apiUrl }?module=contract&action=getabi&address=${ addressString(parsedSourceCode.value.result[0].Implementation) }&apiKey=${ api.apiKey }`) if (!implReq.success) return implReq const implResult = EtherscanGetABIResult.safeParse(implReq.result) - - const sourceCodeResult = await fetchJson(`https://api.etherscan.io/api?module=contract&action=getsourcecode&address=${ addressString(parsedSourceCode.value.result[0].Implementation) }&apiKey=${ EtherscanABIKey }`) + + const sourceCodeResult = await fetchJson(`${ api.apiUrl }?module=contract&action=getsourcecode&address=${ addressString(parsedSourceCode.value.result[0].Implementation) }&apiKey=${ api.apiKey }`) if (!sourceCodeResult.success) return sourceCodeResult const implementationName = EtherscanSourceCodeResult.safeParse(sourceCodeResult.result) diff --git a/app/ts/types/interceptor-messages.ts b/app/ts/types/interceptor-messages.ts index fe231caa..9867ef4d 100644 --- a/app/ts/types/interceptor-messages.ts +++ b/app/ts/types/interceptor-messages.ts @@ -776,18 +776,19 @@ const PopupAddOrModifyAddressWindowStateInfomation = funtypes.ReadonlyObject({ }) }) -export type FetchAbiAndNameFromEtherscan = funtypes.Static -export const FetchAbiAndNameFromEtherscan = funtypes.ReadonlyObject({ - method: funtypes.Literal('popup_fetchAbiAndNameFromEtherscan'), +export type FetchAbiAndNameFromBlockExplorer = funtypes.Static +export const FetchAbiAndNameFromBlockExplorer = funtypes.ReadonlyObject({ + method: funtypes.Literal('popup_fetchAbiAndNameFromBlockExplorer'), data: funtypes.ReadonlyObject({ windowStateId: funtypes.String, - address: EthereumAddress + address: EthereumAddress, + chainId: ChainIdWithUniversal, }) }).asReadonly() -type FetchAbiAndNameFromEtherscanReply = funtypes.Static -const FetchAbiAndNameFromEtherscanReply = funtypes.ReadonlyObject({ - method: funtypes.Literal('popup_fetchAbiAndNameFromEtherscanReply'), +type FetchAbiAndNameFromBlockExplorerReply = funtypes.Static +const FetchAbiAndNameFromBlockExplorerReply = funtypes.ReadonlyObject({ + method: funtypes.Literal('popup_fetchAbiAndNameFromBlockExplorerReply'), data: funtypes.Union( funtypes.ReadonlyObject({ windowStateId: funtypes.String, @@ -890,7 +891,7 @@ export const PopupMessage = funtypes.Union( ChangeSettings, SetRpcList, ChangeAddOrModifyAddressWindowState, - FetchAbiAndNameFromEtherscan, + FetchAbiAndNameFromBlockExplorer, OpenWebPage, DisableInterceptor, SetEnsNameForHash, @@ -923,7 +924,7 @@ export const MessageToPopup = funtypes.Union( PartiallyParsedSimulateExecutionReply, SettingsOpenedReply, PopupAddOrModifyAddressWindowStateInfomation, - FetchAbiAndNameFromEtherscanReply, + FetchAbiAndNameFromBlockExplorerReply, DisableInterceptorReply, UnexpectedErrorOccured, RetrieveWebsiteAccessReply, diff --git a/app/ts/types/rpc.ts b/app/ts/types/rpc.ts index 59f9d269..e95baf79 100644 --- a/app/ts/types/rpc.ts +++ b/app/ts/types/rpc.ts @@ -10,6 +10,12 @@ export const ChainEntry = funtypes.Intersect( }), ) +export type BlockExplorer = funtypes.Static +export const BlockExplorer = funtypes.ReadonlyObject({ + apiUrl: funtypes.String, + apiKey: funtypes.String, +}) + export type RpcEntry = funtypes.Static export const RpcEntry = funtypes.Intersect( funtypes.ReadonlyObject({ @@ -23,6 +29,7 @@ export const RpcEntry = funtypes.Intersect( }), funtypes.ReadonlyPartial({ currencyLogoUri: funtypes.String, + blockExplorer: BlockExplorer }) )