diff --git a/packages/sdk/src/config.ts b/packages/sdk/src/config.ts index ace8e31d0..4a3667d30 100644 --- a/packages/sdk/src/config.ts +++ b/packages/sdk/src/config.ts @@ -1,31 +1,3 @@ -export const METHODS_TO_REDIRECT: { [method: string]: boolean } = { - eth_requestAccounts: true, - eth_sendTransaction: true, - eth_signTransaction: true, - eth_sign: true, - eth_accounts: true, - personal_sign: true, - eth_signTypedData: true, - eth_signTypedData_v3: true, - eth_signTypedData_v4: true, - wallet_requestPermissions: true, - wallet_getPermissions: true, - wallet_watchAsset: true, - wallet_addEthereumChain: true, - wallet_switchEthereumChain: true, - metamask_connectSign: true, - metamask_connectWith: true, - personal_ecRecover: true, - metamask_batch: true, - metamask_open: true, -}; - -export const lcAnalyticsRPCs = Object.keys(METHODS_TO_REDIRECT).map((method) => - method.toLowerCase(), -); - -export const STORAGE_PATH = '.sdk-comm'; -export const STORAGE_PROVIDER_TYPE = 'providerType'; export const RPC_METHODS = { METAMASK_GETPROVIDERSTATE: 'metamask_getProviderState', METAMASK_CONNECTSIGN: 'metamask_connectSign', @@ -34,11 +6,59 @@ export const RPC_METHODS = { METAMASK_BATCH: 'metamask_batch', PERSONAL_SIGN: 'personal_sign', WALLET_REQUESTPERMISSIONS: 'wallet_requestPermissions', + WALLET_GETPERMISSIONS: 'wallet_getPermissions', + WALLET_WATCHASSET: 'wallet_watchAsset', + WALLET_ADDETHEREUMCHAIN: 'wallet_addEthereumChain', + WALLET_SWITCHETHETHEREUMCHAIN: 'wallet_switchEthereumChain', ETH_REQUESTACCOUNTS: 'eth_requestAccounts', ETH_ACCOUNTS: 'eth_accounts', ETH_CHAINID: 'eth_chainId', + ETH_SENDTRANSACTION: 'eth_sendTransaction', + ETH_SIGNTYPEDDATA: 'eth_signTypedData', + ETH_SIGNTYPEDDATA_V3: 'eth_signTypedData_v3', + ETH_SIGNTYPEDDATA_V4: 'eth_signTypedData_v4', + ETH_SIGNTRANSACTION: 'eth_signTransaction', + ETH_SIGN: 'eth_sign', + PERSONAL_EC_RECOVER: 'personal_ecRecover', +}; + +export const METHODS_TO_REDIRECT: { [method: string]: boolean } = { + [RPC_METHODS.ETH_REQUESTACCOUNTS]: true, + [RPC_METHODS.ETH_SENDTRANSACTION]: true, + [RPC_METHODS.ETH_SIGNTRANSACTION]: true, + [RPC_METHODS.ETH_SIGN]: true, + [RPC_METHODS.ETH_ACCOUNTS]: true, + [RPC_METHODS.PERSONAL_SIGN]: true, + [RPC_METHODS.ETH_SIGNTYPEDDATA]: true, + [RPC_METHODS.ETH_SIGNTYPEDDATA_V3]: true, + [RPC_METHODS.ETH_SIGNTYPEDDATA_V4]: true, + [RPC_METHODS.WALLET_REQUESTPERMISSIONS]: true, + [RPC_METHODS.WALLET_GETPERMISSIONS]: true, + [RPC_METHODS.WALLET_WATCHASSET]: true, + [RPC_METHODS.WALLET_ADDETHEREUMCHAIN]: true, + [RPC_METHODS.WALLET_SWITCHETHETHEREUMCHAIN]: true, + [RPC_METHODS.METAMASK_CONNECTSIGN]: true, + [RPC_METHODS.METAMASK_CONNECTWITH]: true, + [RPC_METHODS.PERSONAL_EC_RECOVER]: true, + [RPC_METHODS.METAMASK_BATCH]: true, + [RPC_METHODS.METAMASK_OPEN]: true, }; +export const lcAnalyticsRPCs = Object.keys(METHODS_TO_REDIRECT).map((method) => + method.toLowerCase(), +); + +// unsupported extension connectWith methods +export const rpcWithAccountParam = [ + 'eth_signTypedData', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + 'eth_sign', +].map((method) => method.toLowerCase()); + +export const STORAGE_PATH = '.sdk-comm'; +export const STORAGE_PROVIDER_TYPE = 'providerType'; + export const EXTENSION_EVENTS = { CHAIN_CHANGED: 'chainChanged', ACCOUNTS_CHANGED: 'accountsChanged', diff --git a/packages/sdk/src/provider/extensionConnectWithOverwrite.ts b/packages/sdk/src/provider/extensionConnectWithOverwrite.ts new file mode 100644 index 000000000..e235e1334 --- /dev/null +++ b/packages/sdk/src/provider/extensionConnectWithOverwrite.ts @@ -0,0 +1,66 @@ +import { rpcWithAccountParam, RPC_METHODS } from '../config'; +import { MetaMaskSDK } from '../sdk'; +import { logger } from '../utils/logger'; + +export const extensionConnectWithOverwrite = async ({ + method, + sdk, + params, +}: { + method: string; + sdk: MetaMaskSDK; + params: any; +}) => { + if (!sdk.isExtensionActive()) { + throw new Error(`SDK state invalid -- extension is not active`); + } + + logger( + `[MetaMaskProvider: extensionConnectWithOverwrite()] Overwriting request method`, + method, + params, + ); + + const accounts = (await sdk.getProvider()?.request({ + method: RPC_METHODS.ETH_REQUESTACCOUNTS, + params: [], + })) as string[]; + if (!accounts.length) { + throw new Error(`SDK state invalid -- undefined accounts`); + } + + if (method?.toLowerCase() === RPC_METHODS.PERSONAL_SIGN.toLowerCase()) { + const connectedRpc = { + method, + params: [params[0], accounts[0]], + }; + return await sdk.getProvider()?.request(connectedRpc); + } else if ( + method?.toLowerCase() === RPC_METHODS.ETH_SENDTRANSACTION.toLowerCase() + ) { + const connectedRpc = { + method, + params: [ + { + ...params[0], + from: accounts[0], + }, + ], + }; + return await sdk.getProvider()?.request(connectedRpc); + } + + // TODO: implement overwrite for each remaining signedTyped methods + if (rpcWithAccountParam.includes(method.toLowerCase())) { + console.warn( + `MetaMaskSDK connectWith method=${method} -- not handled by the extension -- call separately`, + ); + return accounts; + } + + // Re-create the query on the active provider + return await sdk.getProvider()?.request({ + method, + params, + }); +}; diff --git a/packages/sdk/src/provider/initializeMobileProvider.ts b/packages/sdk/src/provider/initializeMobileProvider.ts index 3bfd8f7a8..a36f27ca2 100644 --- a/packages/sdk/src/provider/initializeMobileProvider.ts +++ b/packages/sdk/src/provider/initializeMobileProvider.ts @@ -16,6 +16,7 @@ import { rpcRequestHandler } from '../services/rpc-requests/RPCRequestHandler'; import { PROVIDER_UPDATE_TYPE } from '../types/ProviderUpdateType'; import { logger } from '../utils/logger'; import { wait } from '../utils/wait'; +import { extensionConnectWithOverwrite } from './extensionConnectWithOverwrite'; const initializeMobileProvider = ({ checkInstallationOnAllCalls = false, @@ -193,6 +194,8 @@ const initializeMobileProvider = ({ (!isInstalled || (isInstalled && !socketConnected)) && method !== RPC_METHODS.METAMASK_GETPROVIDERSTATE ) { + const params = args?.[0]?.params || []; + if ( ALLOWED_CONNECT_METHODS.indexOf(method) !== -1 || checkInstallationOnAllCalls @@ -217,8 +220,6 @@ const initializeMobileProvider = ({ method.toLowerCase() === RPC_METHODS.METAMASK_CONNECTSIGN.toLowerCase() ) { - const [temp] = args; - const { params } = temp; const accounts = (await sdk.getProvider()?.request({ method: RPC_METHODS.ETH_REQUESTACCOUNTS, params: [], @@ -235,38 +236,23 @@ const initializeMobileProvider = ({ method.toLowerCase() === RPC_METHODS.METAMASK_CONNECTWITH.toLowerCase() ) { - const accounts = (await sdk.getProvider()?.request({ - method: RPC_METHODS.ETH_REQUESTACCOUNTS, - params: [], - })) as string[]; - if (!accounts.length) { - throw new Error(`SDK state invalid -- undefined accounts`); - } - - const [initialMethod] = args; - console.log(`connectWith:: initialMethod`, initialMethod); - const { params } = initialMethod; const [rpc] = params; - console.warn(`FIXME:: handle CONNECT_WITH`, rpc); - - if ( - rpc.method?.toLowerCase() === - RPC_METHODS.PERSONAL_SIGN.toLowerCase() - ) { - const connectedRpc = { - method: rpc.method, - params: [rpc.params[0], accounts[0]], - }; - console.log(`connectWith:: connectedRpc`, connectedRpc); - return await sdk.getProvider()?.request(connectedRpc); - } - console.warn(`FIXME:: handle CONNECT_WITH`, rpc); + // Overwrite rpc method with correct account information + return await extensionConnectWithOverwrite({ + method: rpc.method, + sdk, + params: rpc.params, + }); } + logger( + `[initializeMobileProvider: sendRequest()] sending '${method}' on active provider`, + params, + ); // Re-create the query on the active provider return await sdk.getProvider()?.request({ method, - params: args, + params, }); } @@ -309,7 +295,7 @@ const initializeMobileProvider = ({ // Re-create the query on the active provider return await sdk.getProvider()?.request({ method, - params: args, + params, }); } throw err; @@ -327,12 +313,14 @@ const initializeMobileProvider = ({ // It means there was a switch of provider while waiting for initialization -- redirect to the extension. logger( `[initializeMobileProvider: sendRequest()] EXTENSION active - redirect request '${method}' to it`, + args, + params, ); // redirect to extension return await sdk.getProvider()?.request({ method, - params: args, + params, }); }