From 5a56047d55201d01ca4f213cb44fdf709c37d42c Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 31 Jan 2024 09:59:10 +0100 Subject: [PATCH] dedupe providers and fix various issues --- extension/.cspell.json | 1 + extension/.pnp.cjs | 14 -- extension/.vscode/settings.json | 2 +- ...ovider-npm-5.7.0-f94be4e0b0-74cf469624.zip | Bin 21866 -> 21860 bytes ...mental-npm-5.7.0-692be0d4ae-a4973371be.zip | Bin 41476 -> 0 bytes extension/package.json | 1 - extension/src/browser/Drawer/Submit.tsx | 11 +- extension/src/browser/Frame.tsx | 8 +- extension/src/providers/ProvideTenderly.tsx | 148 ++++++++------- extension/src/providers/WrappingProvider.ts | 5 +- extension/src/providers/readOnlyProvider.ts | 176 ++++++++++++++++++ extension/src/providers/useMetaMask.tsx | 2 +- extension/src/providers/useWalletConnect.ts | 8 +- extension/src/safe/kits.ts | 14 +- extension/src/safe/sendTransaction.ts | 22 +-- extension/src/safe/useSafeDelegates.ts | 2 +- extension/src/safe/useSafesWithOwner.ts | 6 +- .../src/safe/waitForMultisigExecution.ts | 4 +- extension/src/settings/connectionHooks.tsx | 81 +++----- extension/yarn.lock | 14 +- 20 files changed, 320 insertions(+), 199 deletions(-) delete mode 100644 extension/.yarn/cache/@ethersproject-experimental-npm-5.7.0-692be0d4ae-a4973371be.zip create mode 100644 extension/src/providers/readOnlyProvider.ts diff --git a/extension/.cspell.json b/extension/.cspell.json index a18fc161..1be2fc4a 100644 --- a/extension/.cspell.json +++ b/extension/.cspell.json @@ -14,6 +14,7 @@ "blockies", "borderless", "Bytecode", + "ccip", "cowswap", "Delegatecall", "delegatecalls", diff --git a/extension/.pnp.cjs b/extension/.pnp.cjs index a14095ed..1fe983b0 100755 --- a/extension/.pnp.cjs +++ b/extension/.pnp.cjs @@ -30,7 +30,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageDependencies": [\ ["@ethersproject/abi", "npm:5.7.0"],\ ["@ethersproject/abstract-provider", "npm:5.7.0"],\ - ["@ethersproject/experimental", "npm:5.7.0"],\ ["@ethersproject/providers", "npm:5.7.2"],\ ["@gnosis.pm/zodiac", "npm:3.4.2"],\ ["@safe-global/api-kit", "npm:1.3.1"],\ @@ -1912,18 +1911,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@ethersproject/experimental", [\ - ["npm:5.7.0", {\ - "packageLocation": "./.yarn/cache/@ethersproject-experimental-npm-5.7.0-692be0d4ae-a4973371be.zip/node_modules/@ethersproject/experimental/",\ - "packageDependencies": [\ - ["@ethersproject/experimental", "npm:5.7.0"],\ - ["@ethersproject/web", "npm:5.7.1"],\ - ["ethers", "npm:5.7.2"],\ - ["scrypt-js", "npm:3.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@ethersproject/hash", [\ ["npm:5.7.0", {\ "packageLocation": "./.yarn/cache/@ethersproject-hash-npm-5.7.0-7c00366b4e-6e9fa8d14e.zip/node_modules/@ethersproject/hash/",\ @@ -17180,7 +17167,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["zodiac-pilot", "workspace:."],\ ["@ethersproject/abi", "npm:5.7.0"],\ ["@ethersproject/abstract-provider", "npm:5.7.0"],\ - ["@ethersproject/experimental", "npm:5.7.0"],\ ["@ethersproject/providers", "npm:5.7.2"],\ ["@gnosis.pm/zodiac", "npm:3.4.2"],\ ["@safe-global/api-kit", "npm:1.3.1"],\ diff --git a/extension/.vscode/settings.json b/extension/.vscode/settings.json index 7ed27fa3..b97b1ce3 100644 --- a/extension/.vscode/settings.json +++ b/extension/.vscode/settings.json @@ -6,7 +6,7 @@ "typescript.tsdk": ".yarn/sdks/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "jest.jestCommandLine": "yarn test", "search.exclude": { diff --git a/extension/.yarn/cache/@ethersproject-abstract-provider-npm-5.7.0-f94be4e0b0-74cf469624.zip b/extension/.yarn/cache/@ethersproject-abstract-provider-npm-5.7.0-f94be4e0b0-74cf469624.zip index 5f6e6bedc9e42b13c64eded277b6d98618ea250b..7767845a4132936ff1b54a6bf2b3068e53fc980b 100644 GIT binary patch delta 2793 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 BV37a- diff --git a/extension/.yarn/cache/@ethersproject-experimental-npm-5.7.0-692be0d4ae-a4973371be.zip b/extension/.yarn/cache/@ethersproject-experimental-npm-5.7.0-692be0d4ae-a4973371be.zip deleted file mode 100644 index af155546738c403c7a0e214fbebeafe28df25525..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41476 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�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 diff --git a/extension/package.json b/extension/package.json index cc7b091e..ed9d31bf 100644 --- a/extension/package.json +++ b/extension/package.json @@ -25,7 +25,6 @@ "devDependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/experimental": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@gnosis.pm/zodiac": "^3.4.2", "@safe-global/api-kit": "^1.3.1", diff --git a/extension/src/browser/Drawer/Submit.tsx b/extension/src/browser/Drawer/Submit.tsx index 30ec7849..53b623e8 100644 --- a/extension/src/browser/Drawer/Submit.tsx +++ b/extension/src/browser/Drawer/Submit.tsx @@ -1,4 +1,3 @@ -import { providers } from 'ethers' import React, { useState } from 'react' import { RiCloseLine, RiExternalLinkLine } from 'react-icons/ri' import Modal, { Styles } from 'react-modal' @@ -16,9 +15,10 @@ import { useSubmitTransactions } from '../ProvideProvider' import { useDispatch, useNewTransactions } from '../state' import classes from './style.module.css' +import { getReadOnlyProvider } from '../../providers/readOnlyProvider' const Submit: React.FC = () => { - const { provider, connection } = useConnection() + const { connection } = useConnection() const { chainId, pilotAddress, providerType } = connection const dispatch = useDispatch() @@ -61,16 +61,15 @@ const Submit: React.FC = () => { // wait for transaction to be mined const realBatchTransactionHash = await waitForMultisigExecution( - provider, chainId, batchTransactionHash ) console.log( `Transaction batch ${batchTransactionHash} has been executed with transaction hash ${realBatchTransactionHash}` ) - const receipt = await new providers.Web3Provider( - provider - ).waitForTransaction(realBatchTransactionHash) + const receipt = await getReadOnlyProvider(chainId).waitForTransaction( + realBatchTransactionHash + ) console.log( `Transaction ${realBatchTransactionHash} has been mined`, receipt diff --git a/extension/src/browser/Frame.tsx b/extension/src/browser/Frame.tsx index 9c84463b..4b269054 100644 --- a/extension/src/browser/Frame.tsx +++ b/extension/src/browser/Frame.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react' +import React, { useLayoutEffect, useRef } from 'react' import Eip1193Bridge from '../bridge/Eip1193Bridge' import SafeAppBridge from '../bridge/SafeAppBridge' @@ -16,7 +16,10 @@ const BrowserFrame: React.FC = ({ src }) => { const eip1193BridgeRef = useRef(null) const safeAppBridgeRef = useRef(null) - useEffect(() => { + // We need the message listener to be set up before the iframe content window is loaded. + // Otherwise we might miss the initial handshake message from the Safe SDK. + // Using a layout effect ensures that the listeners are set synchronously after DOM flush. + useLayoutEffect(() => { if (!provider) return // establish EIP-1193 bridge @@ -40,7 +43,6 @@ const BrowserFrame: React.FC = ({ src }) => { safeAppBridgeRef.current?.handleMessage(ev) } window.addEventListener('message', handle) - console.log('messages will be handled') return () => { window.removeEventListener('message', handle) diff --git a/extension/src/providers/ProvideTenderly.tsx b/extension/src/providers/ProvideTenderly.tsx index 893e9c2e..60c5dbf8 100644 --- a/extension/src/providers/ProvideTenderly.tsx +++ b/extension/src/providers/ProvideTenderly.tsx @@ -1,94 +1,56 @@ import EventEmitter from 'events' import { JsonRpcProvider } from '@ethersproject/providers' -import React, { useContext, useEffect, useState } from 'react' +import React, { useContext, useEffect, useMemo } from 'react' import { useConnection } from '../settings/connectionHooks' import { Eip1193Provider, JsonRpcRequest } from '../types' import { useBeforeUnload } from '../utils' import { initSafeProtocolKit } from '../safe/kits' import { safeInterface } from '../safe' +import { getEip1193ReadOnlyProvider } from './readOnlyProvider' +import { ChainId } from '../chains' const TenderlyContext = React.createContext(null) -export const useTenderlyProvider = (): TenderlyProvider | null => - useContext(TenderlyContext) +export const useTenderlyProvider = (): TenderlyProvider => { + const value = useContext(TenderlyContext) + if (!value) throw new Error('must be wrapped in ') + return value +} + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const ProvideTenderly: React.FC<{ children: React.ReactNode }> = ({ children, }) => { - const { provider, chainId, connection } = useConnection() + const { + connection: { chainId, avatarAddress, moduleAddress, pilotAddress }, + } = useConnection() - const [tenderlyProvider, setTenderlyProvider] = - useState(null) + const tenderlyProvider = useMemo(() => { + return new TenderlyProvider(chainId) + }, [chainId]) + // whenever anything changes in the connection settings, we delete the current fork and start afresh useEffect(() => { - if (!chainId) return - - const tenderlyProvider = new TenderlyProvider(provider, chainId) - setTenderlyProvider(tenderlyProvider) - - const canceled = false - async function prepareSafeForSimulation() { - const { avatarAddress, moduleAddress, pilotAddress } = connection - const safe = await initSafeProtocolKit(provider, avatarAddress) - - // If we simulate as a Safe owner, we might have to override the owners & threshold of the Safe to allow single signature transactions - if (!moduleAddress) { - const [owners, threshold] = await Promise.all([ - safe.getOwners(), - safe.getThreshold(), - ]) - - const pilotIsOwner = owners.some( - (owner) => owner.toLowerCase() === pilotAddress.toLowerCase() - ) - - if (!pilotIsOwner) { - // the pilot account is not an owner, so we need to make it one and set the threshold to 1 at the same time - await tenderlyProvider.request({ - method: 'eth_sendTransaction', - params: [ - { - to: avatarAddress, - data: safeInterface.encodeFunctionData( - 'addOwnerWithThreshold', - [pilotAddress, 1] - ), - from: avatarAddress, - }, - ], - }) - } else if (threshold > 1) { - // doesn't allow to execute with single signature, so we need to override the threshold - await tenderlyProvider.request({ - method: 'eth_sendTransaction', - params: [ - { - to: avatarAddress, - data: safeInterface.encodeFunctionData('changeThreshold', [1]), - from: avatarAddress, - }, - ], - }) - } - } - - if (!canceled) return - } - - prepareSafeForSimulation() + prepareSafeForSimulation( + { chainId, avatarAddress, moduleAddress, pilotAddress }, + tenderlyProvider + ) return () => { tenderlyProvider.deleteFork() } - }, [provider, chainId, connection]) + }, [tenderlyProvider, chainId, avatarAddress, moduleAddress, pilotAddress]) // delete fork when closing browser tab (the effect teardown won't be executed in that case) useBeforeUnload(() => { if (tenderlyProvider) tenderlyProvider.deleteFork() }) + if (!tenderlyProvider) return null + return ( {children} @@ -98,6 +60,64 @@ const ProvideTenderly: React.FC<{ children: React.ReactNode }> = ({ export default ProvideTenderly +async function prepareSafeForSimulation( + { + chainId, + avatarAddress, + moduleAddress, + pilotAddress, + }: { + chainId: ChainId + avatarAddress: string + moduleAddress: string + pilotAddress: string + }, + tenderlyProvider: TenderlyProvider +) { + const safe = await initSafeProtocolKit(chainId, avatarAddress) + + // If we simulate as a Safe owner, we might have to override the owners & threshold of the Safe to allow single signature transactions + if (!moduleAddress) { + const [owners, threshold] = await Promise.all([ + safe.getOwners(), + safe.getThreshold(), + ]) + + const pilotIsOwner = owners.some( + (owner) => owner.toLowerCase() === pilotAddress.toLowerCase() + ) + + if (!pilotIsOwner) { + // the pilot account is not an owner, so we need to make it one and set the threshold to 1 at the same time + await tenderlyProvider.request({ + method: 'eth_sendTransaction', + params: [ + { + to: avatarAddress, + data: safeInterface.encodeFunctionData('addOwnerWithThreshold', [ + pilotAddress, + 1, + ]), + from: avatarAddress, + }, + ], + }) + } else if (threshold > 1) { + // doesn't allow to execute with single signature, so we need to override the threshold + await tenderlyProvider.request({ + method: 'eth_sendTransaction', + params: [ + { + to: avatarAddress, + data: safeInterface.encodeFunctionData('changeThreshold', [1]), + from: avatarAddress, + }, + ], + }) + } + } +} + export interface TenderlyTransactionInfo { id: string project_id: string @@ -157,9 +177,9 @@ export class TenderlyProvider extends EventEmitter { private tenderlyForkApi: string - constructor(provider: Eip1193Provider, chainId: number) { + constructor(chainId: ChainId) { super() - this.provider = provider + this.provider = getEip1193ReadOnlyProvider(chainId, ZERO_ADDRESS) this.chainId = chainId this.tenderlyForkApi = 'https://fork-api.pilot.gnosisguild.org' } diff --git a/extension/src/providers/WrappingProvider.ts b/extension/src/providers/WrappingProvider.ts index bd3580bf..697afce3 100644 --- a/extension/src/providers/WrappingProvider.ts +++ b/extension/src/providers/WrappingProvider.ts @@ -95,10 +95,7 @@ class WrappingProvider extends EventEmitter { if (!this.connection.moduleAddress) { // use safeTxGas estimation for direct execution - const safeApiKit = initSafeApiKit( - this.provider, - this.connection.chainId - ) + const safeApiKit = initSafeApiKit(this.connection.chainId) const result = await safeApiKit.estimateSafeTransaction( this.connection.avatarAddress, request diff --git a/extension/src/providers/readOnlyProvider.ts b/extension/src/providers/readOnlyProvider.ts new file mode 100644 index 00000000..3df7523b --- /dev/null +++ b/extension/src/providers/readOnlyProvider.ts @@ -0,0 +1,176 @@ +import EventEmitter from 'events' +import { hexValue } from 'ethers/lib/utils' +import { + JsonRpcBatchProvider, + TransactionRequest, +} from '@ethersproject/providers' +import { ChainId, RPC } from '../chains' + +const readOnlyProviderCache = new Map() +const eip1193ProviderCache = new Map() + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' + +export const getReadOnlyProvider = (chainId: ChainId): JsonRpcBatchProvider => { + if (readOnlyProviderCache.has(chainId)) { + return readOnlyProviderCache.get(chainId)! + } + + const provider = new JsonRpcBatchProvider(RPC[chainId], chainId) + readOnlyProviderCache.set(chainId, provider) + return provider +} + +/** + * Returns a read-only EIP-1193 provider powered by our RPC nodes. This provider is useful for reading data from the blockchain, but cannot be used to sign transactions. + * Memoizes the provider to avoid triggering effect cascades. + * @throws if used for wallet RPC calls + **/ +export const getEip1193ReadOnlyProvider = ( + chainId: ChainId, + address: string +): Eip1193JsonRpcProvider => { + const cacheKey = `${chainId}:${address.toLowerCase()}` + if (eip1193ProviderCache.has(cacheKey)) { + return eip1193ProviderCache.get(cacheKey)! + } + + const provider = new Eip1193JsonRpcProvider(chainId) + eip1193ProviderCache.set(cacheKey, provider) + return provider +} + +const hexlifyTransaction = (transaction: TransactionRequest) => + JsonRpcBatchProvider.hexlifyTransaction(transaction, { + from: true, + customData: true, + ccipReadEnabled: true, + }) + +/** + * Based on the ethers v5 Eip1193Bridge (https://github.com/ethers-io/ethers.js/blob/v5.7/packages/experimental/src.ts/eip1193-bridge.ts) + * Copyright (c) 2019 Richard Moore, released under MIT license. + */ +export class Eip1193JsonRpcProvider extends EventEmitter { + readonly provider: JsonRpcBatchProvider + readonly chainId: ChainId + readonly address: string + + constructor(chainId: ChainId, address: string = ZERO_ADDRESS) { + super() + this.chainId = chainId + this.address = address + this.provider = getReadOnlyProvider(chainId) + } + + request(request: { method: string; params?: Array }): Promise { + return this.send(request.method, request.params || []) + } + + async send(method: string, params: any[] = []): Promise { + let coerce = (value: any) => value + + switch (method) { + case 'eth_gasPrice': { + const result = await this.provider.getGasPrice() + return result.toHexString() + } + case 'eth_accounts': { + return this.address === ZERO_ADDRESS ? [] : [this.address] + } + case 'eth_blockNumber': { + return await this.provider.getBlockNumber() + } + case 'eth_chainId': { + return hexValue(this.chainId) + } + case 'eth_getBalance': { + const result = await this.provider.getBalance(params[0], params[1]) + return result.toHexString() + } + case 'eth_getStorageAt': { + return this.provider.getStorageAt(params[0], params[1], params[2]) + } + case 'eth_getTransactionCount': { + const result = await this.provider.getTransactionCount( + params[0], + params[1] + ) + return hexValue(result) + } + case 'eth_getBlockTransactionCountByHash': + case 'eth_getBlockTransactionCountByNumber': { + const result = await this.provider.getBlock(params[0]) + return hexValue(result.transactions.length) + } + case 'eth_getCode': { + const result = await this.provider.getCode(params[0], params[1]) + return result + } + case 'eth_sendRawTransaction': { + return await this.provider.sendTransaction(params[0]) + } + case 'eth_call': { + const req = hexlifyTransaction(params[0]) + return await this.provider.call(req, params[1]) + } + case 'estimateGas': { + if (params[1] && params[1] !== 'latest') { + throw new Error('estimateGas does not support blockTag') + } + + const req = hexlifyTransaction(params[0]) + const result = await this.provider.estimateGas(req) + return result.toHexString() + } + + // @TODO: Transform? No uncles? + case 'eth_getBlockByHash': + case 'eth_getBlockByNumber': { + if (params[1]) { + return await this.provider.getBlockWithTransactions(params[0]) + } else { + return await this.provider.getBlock(params[0]) + } + } + case 'eth_getTransactionByHash': { + return await this.provider.getTransaction(params[0]) + } + case 'eth_getTransactionReceipt': { + return await this.provider.getTransactionReceipt(params[0]) + } + + case 'eth_sendTransaction': + case 'eth_sign': { + throw new Error(`${method} requires signing`) + } + + case 'eth_getUncleCountByBlockHash': + case 'eth_getUncleCountByBlockNumber': { + coerce = hexValue + break + } + + case 'eth_getTransactionByBlockHashAndIndex': + case 'eth_getTransactionByBlockNumberAndIndex': + case 'eth_getUncleByBlockHashAndIndex': + case 'eth_getUncleByBlockNumberAndIndex': + case 'eth_newFilter': + case 'eth_newBlockFilter': + case 'eth_newPendingTransactionFilter': + case 'eth_uninstallFilter': + case 'eth_getFilterChanges': + case 'eth_getFilterLogs': + case 'eth_getLogs': + break + } + + // If our provider supports send, maybe it can do a better job? + if ((this.provider).send) { + const result = this.provider.send(method, params) + return coerce(result) + } + + return new Error(`unsupported method: ${method}`) + } +} diff --git a/extension/src/providers/useMetaMask.tsx b/extension/src/providers/useMetaMask.tsx index ce72949d..cb4bffd5 100644 --- a/extension/src/providers/useMetaMask.tsx +++ b/extension/src/providers/useMetaMask.tsx @@ -18,7 +18,7 @@ import { } from '../chains' import { Eip1193Provider } from '../types' -interface MetaMaskContextT { +export interface MetaMaskContextT { provider: Eip1193Provider | undefined connect: () => Promise<{ chainId: number; accounts: string[] }> switchChain: (chainId: ChainId) => Promise diff --git a/extension/src/providers/useWalletConnect.ts b/extension/src/providers/useWalletConnect.ts index a92200fd..082b8b8d 100644 --- a/extension/src/providers/useWalletConnect.ts +++ b/extension/src/providers/useWalletConnect.ts @@ -68,11 +68,7 @@ class WalletConnectEthereumMultiProvider extends WalletConnectEthereumProvider { if (method === 'eth_sendTransaction') { const safeTxHash = (await requestWithCorrectErrors(request)) as string - const txHash = await waitForMultisigExecution( - this.signer, - this.chainId, - safeTxHash - ) + const txHash = await waitForMultisigExecution(this.chainId, safeTxHash) return txHash } @@ -127,7 +123,7 @@ class WalletConnectJsonRpcError extends Error implements JsonRpcError { } } -interface WalletConnectResult { +export interface WalletConnectResult { provider: WalletConnectEthereumMultiProvider connected: boolean connect(): Promise<{ chainId: number; accounts: string[] }> diff --git a/extension/src/safe/kits.ts b/extension/src/safe/kits.ts index 250f8356..003b93ff 100644 --- a/extension/src/safe/kits.ts +++ b/extension/src/safe/kits.ts @@ -3,7 +3,7 @@ import SafeApiKit from '@safe-global/api-kit' import * as ethers from 'ethers' import { ChainId } from '../chains' -import { Eip1193Provider } from '../types' +import { getReadOnlyProvider } from '../providers/readOnlyProvider' export const TX_SERVICE_URL: Record = { [1]: 'https://safe-transaction-mainnet.safe.global', @@ -20,9 +20,7 @@ export const TX_SERVICE_URL: Record = { [80001]: undefined, // not available } -export const initSafeApiKit = (provider: Eip1193Provider, chainId: ChainId) => { - const web3Provider = new ethers.providers.Web3Provider(provider) - +export const initSafeApiKit = (chainId: ChainId) => { const txServiceUrl = TX_SERVICE_URL[chainId as ChainId] if (!txServiceUrl) { throw new Error(`service not available for chain #${chainId}`) @@ -30,21 +28,19 @@ export const initSafeApiKit = (provider: Eip1193Provider, chainId: ChainId) => { const ethAdapter = new EthersAdapter({ ethers, - signerOrProvider: web3Provider.getSigner(), + signerOrProvider: getReadOnlyProvider(chainId), }) return new SafeApiKit({ txServiceUrl, ethAdapter }) } export const initSafeProtocolKit = async ( - provider: Eip1193Provider, + chainId: ChainId, safeAddress: string ) => { - const web3Provider = new ethers.providers.Web3Provider(provider) - const ethAdapter = new EthersAdapter({ ethers, - signerOrProvider: web3Provider.getSigner(), + signerOrProvider: getReadOnlyProvider(chainId), }) return await Safe.create({ ethAdapter, safeAddress }) diff --git a/extension/src/safe/sendTransaction.ts b/extension/src/safe/sendTransaction.ts index d0110374..119efdef 100644 --- a/extension/src/safe/sendTransaction.ts +++ b/extension/src/safe/sendTransaction.ts @@ -2,20 +2,18 @@ import Safe, { EthersAdapter } from '@safe-global/protocol-kit' import * as ethers from 'ethers' import { getAddress } from 'ethers/lib/utils' import { MetaTransaction } from 'react-multisend' +import { getReadOnlyProvider } from '../providers/readOnlyProvider' import { Connection, Eip1193Provider, TransactionData } from '../types' import { initSafeApiKit } from './kits' import { waitForMultisigExecution } from './waitForMultisigExecution' -export const shallExecuteDirectly = async ( - provider: Eip1193Provider, - connection: Connection -) => { - const web3Provider = new ethers.providers.Web3Provider(provider) +export const shallExecuteDirectly = async (connection: Connection) => { + const provider = getReadOnlyProvider(connection.chainId) const ethAdapter = new EthersAdapter({ ethers, - signerOrProvider: web3Provider.getSigner(), + signerOrProvider: provider, }) const safeSdk = await Safe.create({ ethAdapter, @@ -24,7 +22,7 @@ export const shallExecuteDirectly = async ( const threshold = await safeSdk.getThreshold() const pilotIsSmartAccount = - (await web3Provider.getCode(connection.pilotAddress)) !== '0x' + (await provider.getCode(connection.pilotAddress)) !== '0x' return !connection.moduleAddress && threshold === 1 && pilotIsSmartAccount } @@ -41,7 +39,7 @@ export const sendTransaction = async ( } const web3Provider = new ethers.providers.Web3Provider(provider) - const safeApiKit = initSafeApiKit(provider, connection.chainId) + const safeApiKit = initSafeApiKit(connection.chainId) const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: web3Provider.getSigner(), @@ -66,7 +64,7 @@ export const sendTransaction = async ( }) const safeTxHash = await safeSdk.getTransactionHash(safeTransaction) - if (await shallExecuteDirectly(provider, connection)) { + if (await shallExecuteDirectly(connection)) { // we execute the transaction directly. this way the pilot safe can collect signatures for the exec transaction (giving more context to co-signers) rather than for signing a meta transaction await safeSdk.executeTransaction(safeTransaction) } else { @@ -83,11 +81,7 @@ export const sendTransaction = async ( }) } - return await waitForMultisigExecution( - provider, - connection.chainId, - safeTxHash - ) + return await waitForMultisigExecution(connection.chainId, safeTxHash) } const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' diff --git a/extension/src/safe/useSafeDelegates.ts b/extension/src/safe/useSafeDelegates.ts index 4306f60c..d65e5c38 100644 --- a/extension/src/safe/useSafeDelegates.ts +++ b/extension/src/safe/useSafeDelegates.ts @@ -20,7 +20,7 @@ export const useSafeDelegates = ( useEffect(() => { if (!chainId || !checksumSafeAddress) return - const safeApiKit = initSafeApiKit(provider, chainId as ChainId) + const safeApiKit = initSafeApiKit(chainId as ChainId) setLoading(true) let canceled = false diff --git a/extension/src/safe/useSafesWithOwner.ts b/extension/src/safe/useSafesWithOwner.ts index c76705a6..d9dc49d6 100644 --- a/extension/src/safe/useSafesWithOwner.ts +++ b/extension/src/safe/useSafesWithOwner.ts @@ -10,7 +10,7 @@ export const useSafesWithOwner = ( ownerAddress: string, connectionId?: string ) => { - const { provider, chainId } = useConnection(connectionId) + const { chainId } = useConnection(connectionId) const [loading, setLoading] = useState(false) const [safes, setSafes] = useState([]) @@ -20,7 +20,7 @@ export const useSafesWithOwner = ( useEffect(() => { if (!chainId || !checksumOwnerAddress) return - const safeService = initSafeApiKit(provider, chainId as ChainId) + const safeService = initSafeApiKit(chainId as ChainId) setLoading(true) let canceled = false @@ -44,7 +44,7 @@ export const useSafesWithOwner = ( setSafes([]) canceled = true } - }, [provider, checksumOwnerAddress, chainId]) + }, [checksumOwnerAddress, chainId]) return { loading, safes } } diff --git a/extension/src/safe/waitForMultisigExecution.ts b/extension/src/safe/waitForMultisigExecution.ts index a2ab54d5..707fed3f 100644 --- a/extension/src/safe/waitForMultisigExecution.ts +++ b/extension/src/safe/waitForMultisigExecution.ts @@ -1,14 +1,12 @@ import { ChainId } from '../chains' -import { Eip1193Provider } from '../types' import { initSafeApiKit } from './kits' export function waitForMultisigExecution( - provider: Eip1193Provider, chainId: number, safeTxHash: string ): Promise { - const safeService = initSafeApiKit(provider, chainId as ChainId) + const safeService = initSafeApiKit(chainId as ChainId) return new Promise((resolve, reject) => { function tryAgain() { diff --git a/extension/src/settings/connectionHooks.tsx b/extension/src/settings/connectionHooks.tsx index a81c7189..8155de8a 100644 --- a/extension/src/settings/connectionHooks.tsx +++ b/extension/src/settings/connectionHooks.tsx @@ -1,7 +1,3 @@ -import { EventEmitter } from 'events' - -import { JsonRpcBatchProvider, JsonRpcProvider } from '@ethersproject/providers' -import { Eip1193Bridge } from '@ethersproject/experimental' import { KnownContracts } from '@gnosis.pm/zodiac' import { nanoid } from 'nanoid' import React, { ReactNode, useCallback, useEffect } from 'react' @@ -10,8 +6,9 @@ import { createContext, useContext, useMemo } from 'react' import { useMetaMask, useWalletConnect } from '../providers' import { Connection, Eip1193Provider, ProviderType } from '../types' import { useStickyState, validateAddress } from '../utils' -import { ChainId, RPC } from '../chains' -import { Signer, VoidSigner } from 'ethers' +import { MetaMaskContextT } from '../providers/useMetaMask' +import { WalletConnectResult } from '../providers/useWalletConnect' +import { getEip1193ReadOnlyProvider } from '../providers/readOnlyProvider' const DEFAULT_VALUE: Connection[] = [ { @@ -127,34 +124,15 @@ export const useConnection = (id?: string) => { const metamask = useMetaMask() const walletConnect = useWalletConnect(connection.id, connection.chainId || 1) + const defaultProvider = getEip1193ReadOnlyProvider( + connection.chainId, + connection.pilotAddress + ) const provider: Eip1193Provider = (connection.providerType === ProviderType.MetaMask ? metamask.provider - : walletConnect?.provider) || - new Eip1193Bridge( - // we won't be able to actually sign anything with this provider, so we have to make sure prompt the user to connect their wallet once we need a signature - new VoidSigner( - connection.pilotAddress, - new JsonRpcBatchProvider(RPC[connection.chainId]) - ) - ) - - const isConnectedTo = ( - connectionContext: typeof metamask | typeof walletConnect, - chainId: number, - account: string - ) => { - const accountLower = account.toLowerCase() - return ( - connectionContext && - connectionContext.chainId === chainId && - connectionContext.accounts.some( - (acc) => acc.toLowerCase() === accountLower - ) && - ('connected' in connectionContext ? connectionContext.connected : true) - ) - } + : walletConnect?.provider) || defaultProvider const connected = isConnectedTo( connection.providerType === ProviderType.MetaMask @@ -214,6 +192,23 @@ export const useConnection = (id?: string) => { } } +const isConnectedTo = ( + providerContext: MetaMaskContextT | WalletConnectResult | null, + chainId: number, + account: string +) => { + if (!providerContext) return false + const accountLower = account.toLowerCase() + return ( + providerContext && + providerContext.chainId === chainId && + providerContext.accounts?.some( + (acc) => acc.toLowerCase() === accountLower + ) && + ('connected' in providerContext ? providerContext.connected : true) + ) +} + type ConnectionStateMigration = (connection: Connection) => Connection // If the Connection state structure changes we must lazily migrate users' connections states from the old structure to the new one. @@ -253,29 +248,3 @@ const migrateConnections = (connections: Connection[]): Connection[] => { }) return migratedConnections } - -// export class DummySigner extends Signer { -// public readonly address: string -// public readonly provider: JsonRpcProvider - -// constructor(address: `0x${string}`, chainId: ChainId) { -// super() -// this.address = address -// this.provider = new JsonRpcBatchProvider(RPC[chainId], chainId) -// } - -// async getAddress() { -// return this.address -// } - -// // public getNonce(blockTag?: BlockTag | undefined): Promise { -// // return this.provider.getTransactionCount(this.address, blockTag); -// // } - -// async signMessage(): Promise { -// throw new Error('Method not implemented') -// } -// async signTransaction(): Promise { -// throw new Error('Method not implemented') -// } -// } diff --git a/extension/yarn.lock b/extension/yarn.lock index b1bf7456..11d4fd8e 100644 --- a/extension/yarn.lock +++ b/extension/yarn.lock @@ -1253,17 +1253,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/experimental@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/experimental@npm:5.7.0" - dependencies: - "@ethersproject/web": ^5.7.0 - ethers: ^5.7.0 - scrypt-js: 3.0.1 - checksum: a4973371be9b984d5834df5d6fe3d4d1641204ec859a6d4e11e4a972a3a4a2dd7c0eae6a9a86b90f30faa3633a86ab153197bff6e853fb3ff8f847e0340a3c24 - languageName: node - linkType: hard - "@ethersproject/hash@npm:*, @ethersproject/hash@npm:5.7.0, @ethersproject/hash@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/hash@npm:5.7.0" @@ -6482,7 +6471,7 @@ __metadata: languageName: node linkType: hard -"ethers@npm:^5.7, ethers@npm:^5.7.0, ethers@npm:^5.7.1, ethers@npm:^5.7.2": +"ethers@npm:^5.7, ethers@npm:^5.7.1, ethers@npm:^5.7.2": version: 5.7.2 resolution: "ethers@npm:5.7.2" dependencies: @@ -14450,7 +14439,6 @@ __metadata: dependencies: "@ethersproject/abi": ^5.7.0 "@ethersproject/abstract-provider": ^5.7.0 - "@ethersproject/experimental": ^5.7.0 "@ethersproject/providers": ^5.7.2 "@gnosis.pm/zodiac": ^3.4.2 "@safe-global/api-kit": ^1.3.1