From 45394fc721b9fe43d053a823c87d649db75e80ae Mon Sep 17 00:00:00 2001 From: rileystephens28 Date: Mon, 16 Dec 2024 12:36:14 -0600 Subject: [PATCH 1/2] Increase wallet provider RPC method coverage --- .../services/internal-quai-provider/index.ts | 111 ++++++++++++++---- background/services/provider-bridge/index.ts | 1 + 2 files changed, 91 insertions(+), 21 deletions(-) diff --git a/background/services/internal-quai-provider/index.ts b/background/services/internal-quai-provider/index.ts index 742b08b3..94c96728 100644 --- a/background/services/internal-quai-provider/index.ts +++ b/background/services/internal-quai-provider/index.ts @@ -50,6 +50,7 @@ import { normalizeHexAddress } from "../../utils/addresses" import TransactionService from "../transactions" import { QuaiTransactionRequestWithAnnotation } from "../transactions/types" import { ValidatedAddEthereumChainParameter } from "../provider-bridge/utils" +import { ProviderBridgeDatabase } from "../provider-bridge/db" export type SwitchEthereumChainParameter = { chainId: string @@ -119,7 +120,8 @@ export default class InternalQuaiProviderService extends BaseService { await initializeInternalQuaiDatabase(), await chainService, await transactionService, - await preferenceService + await preferenceService, + new ProviderBridgeDatabase() ) } @@ -127,7 +129,8 @@ export default class InternalQuaiProviderService extends BaseService { private db: InternalQuaiProviderDatabase, private chainService: ChainService, private transactionsService: TransactionService, - private preferenceService: PreferenceService + private preferenceService: PreferenceService, + private providerBridgeDb: ProviderBridgeDatabase ) { super() @@ -279,13 +282,13 @@ export default class InternalQuaiProviderService extends BaseService { ) case "quai_sendTransaction": - return this.sendTransaction( - params[0] as QuaiTransactionRequestWithAnnotation, - origin - ).then((transactionResponse) => transactionResponse.hash) case "eth_sendTransaction": - throw new Error( - "eth_sendTransaction is not supported. You must use quai_sendTransaction instead." + const request = params[0] as QuaiTransactionRequestWithAnnotation & { + maxFeePerGas?: string + maxPriorityFeePerGas?: string + } + return this.sendTransaction(request, origin).then( + (transactionResponse) => transactionResponse.hash ) case "quai_sendRawTransaction": @@ -299,10 +302,13 @@ export default class InternalQuaiProviderService extends BaseService { ) case "quai_gasPrice": + case "eth_gasPrice": return this.chainService.jsonRpcProvider .getFeeData() .then((feeData) => feeData.gasPrice) case "quai_minerTip": + case "eth_minerTip": + case "eth_maxPriorityFeePerGas": return this.chainService.jsonRpcProvider .getFeeData() .then((feeData) => feeData.minerTip) @@ -435,8 +441,32 @@ export default class InternalQuaiProviderService extends BaseService { return this.transactionsService.send(method, params) // unsupported methods - case "net_peerCount": + case "wallet_requestPermissions": + case "wallet_getPermissions": { + const { address } = await this.preferenceService.getSelectedAccount() + const network = await this.getCurrentOrDefaultNetworkForOrigin(origin) + + const permission = await this.providerBridgeDb.checkPermission( + origin, + address, + network.chainID + ) + + if (!permission) { + return [] + } + + // Format according to EIP-2255 + return [ + { + invoker: origin, + parentCapability: "eth_accounts", + caveats: [], + }, + ] + } + case "net_peerCount": case "wallet_accountsChanged": case "wallet_registerOnboarding": default: @@ -467,7 +497,11 @@ export default class InternalQuaiProviderService extends BaseService { } private async sendTransaction( - transactionRequest: QuaiTransactionRequestWithAnnotation, + transactionRequest: QuaiTransactionRequestWithAnnotation & { + gas?: string + maxFeePerGas?: string + maxPriorityFeePerGas?: string + }, origin: string ): Promise { const annotation = @@ -492,19 +526,54 @@ export default class InternalQuaiProviderService extends BaseService { await blockService.pollBlockPricesForNetwork({ network }) await blockService.pollLatestBlock(network) + const payload: QuaiTransactionRequestWithAnnotation & { + gas?: string + maxFeePerGas?: string + maxPriorityFeePerGas?: string + } = { + to, + from, + type: transactionRequest.type || 2, + chainId: network.chainID, + data: transactionRequest.data, + value: transactionRequest.value, + network, + annotation, + } + + // Quai specific fields + if ("gasLimit" in transactionRequest) { + payload.gasLimit = transactionRequest.gasLimit + } + + if ("gasPrice" in transactionRequest) { + payload.gasPrice = transactionRequest.gasPrice + } + + if ("minerTip" in transactionRequest) { + payload.minerTip = transactionRequest.minerTip + } + + // // Ethereum specific fields + if ("gas" in transactionRequest) { + payload.gasLimit = transactionRequest.gas + } + + if ("maxFeePerGas" in transactionRequest) { + payload.gasPrice = transactionRequest.maxFeePerGas + } + + if ("maxPriorityFeePerGas" in transactionRequest) { + payload.minerTip = transactionRequest.maxPriorityFeePerGas + } + + if (typeof transactionRequest.value === "undefined") { + delete payload.value + } + return new Promise((resolve, reject) => { this.emitter.emit("transactionSendRequest", { - payload: { - to, - from, - type: transactionRequest.type, - chainId: network.chainID, - data: transactionRequest.data, - value: transactionRequest.value, - gasLimit: transactionRequest.gasLimit, - network, - annotation, - }, + payload, resolver: resolve, rejecter: reject, }) diff --git a/background/services/provider-bridge/index.ts b/background/services/provider-bridge/index.ts index 57b062cc..836af35c 100644 --- a/background/services/provider-bridge/index.ts +++ b/background/services/provider-bridge/index.ts @@ -568,6 +568,7 @@ export default class ProviderBridgeService extends BaseService { showExtensionPopup(AllowedQueryParamPage.personalSignData) ) case "quai_sendTransaction": + case "eth_sendTransaction": // TODO check this checkPermissionSignTransaction function in future checkPermissionSignTransaction( (params[0] as QuaiTransactionRequest).chainId, From bb2ffa68487b9e3d987a68bcfbf5a64a6f0640b5 Mon Sep 17 00:00:00 2001 From: rileystephens28 Date: Mon, 16 Dec 2024 12:36:31 -0600 Subject: [PATCH 2/2] Improve wallet provider injection logic --- src/window-provider.ts | 74 +++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/window-provider.ts b/src/window-provider.ts index 6223ffa7..b19e082d 100644 --- a/src/window-provider.ts +++ b/src/window-provider.ts @@ -8,7 +8,7 @@ const PELAGUS_OBJECT_PROPERTY = "pelagus" const ETHEREUM_OBJECT_PROPERTY = "ethereum" const WALLET_ROUTER_OBJECT_PROPERTY = "walletRouter" -const DETECT_PROVIDER_INITIALIZATION_EVENT = "quai#initialized" +const DETECT_PROVIDER_INITIALIZATION_EVENT = "pelagus#initialized" const pelagusWindowProvider: PelagusWindowProvider = new PelagusWindowProvider({ postMessage: (data: WindowRequestEvent) => @@ -78,43 +78,49 @@ let cachedWindowEthereumProxy: WindowEthereum // default wallet is changed we are switching the underlying provider. let cachedCurrentProvider: WalletProvider -Object.defineProperty(window, ETHEREUM_OBJECT_PROPERTY, { - get() { - if (!window.walletRouter) { - throw new Error( - `window.${WALLET_ROUTER_OBJECT_PROPERTY} is expected to be set to change the injected provider on window.${ETHEREUM_OBJECT_PROPERTY}.` +if (!window.ethereum) { + Object.defineProperty(window, ETHEREUM_OBJECT_PROPERTY, { + get() { + if (!window.walletRouter) { + throw new Error( + `window.${WALLET_ROUTER_OBJECT_PROPERTY} is expected to be set to change the injected provider on window.${ETHEREUM_OBJECT_PROPERTY}.` + ) + } + + if ( + cachedWindowEthereumProxy && + cachedCurrentProvider === window.walletRouter.currentProvider ) - } + return cachedWindowEthereumProxy - if ( - cachedWindowEthereumProxy && - cachedCurrentProvider === window.walletRouter.currentProvider - ) - return cachedWindowEthereumProxy + cachedWindowEthereumProxy = new Proxy( + window.walletRouter.currentProvider, + { + get(target, prop, receiver) { + if ( + window.walletRouter && + !(prop in window.walletRouter.currentProvider) && + prop in window.walletRouter + ) { + // let's publish the api of `window.walletRoute` also on `window.ethereum` for better discoverability + // @ts-expect-error ts accepts symbols as index only from 4.4 + return window.walletRouter[prop] + } - cachedWindowEthereumProxy = new Proxy(window.walletRouter.currentProvider, { - get(target, prop, receiver) { - if ( - window.walletRouter && - !(prop in window.walletRouter.currentProvider) && - prop in window.walletRouter - ) { - // let's publish the api of `window.walletRoute` also on `window.ethereum` for better discoverability - // @ts-expect-error ts accepts symbols as index only from 4.4 - return window.walletRouter[prop] + return Reflect.get(target, prop, receiver) + }, } + ) + cachedCurrentProvider = window.walletRouter.currentProvider - return Reflect.get(target, prop, receiver) - }, - }) - cachedCurrentProvider = window.walletRouter.currentProvider - - return cachedWindowEthereumProxy - }, - set(newProvider) { - window.walletRouter?.addProvider(newProvider) - }, - configurable: true, -}) + return cachedWindowEthereumProxy + }, + set(newProvider) { + window.walletRouter?.addProvider(newProvider) + }, + writable: true, + configurable: true, + }) +} window.dispatchEvent(new Event(DETECT_PROVIDER_INITIALIZATION_EVENT))