import type Common from '@ethereumjs/common' import type { EIP1193Provider, RPCResponse } from '@web3-onboard/common' import type { CustomNetwork } from './types.js' import type { BigNumber, providers } from 'ethers' /** * Creates the common instance used for signing * transactions with hardware wallets * @returns the initialized common instance */ export const getCommon = async ({ customNetwork, chainId }: { customNetwork?: CustomNetwork chainId: number }): Promise => { const { default: Common, Hardfork } = await import('@ethereumjs/common') // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const CommonConstructor: typeof Common = Common.default || Common const commonOptions = { // Berlin is the minimum hardfork that will allow for EIP1559 hardfork: Hardfork.Berlin, // List of supported EIPS eips: [1559] } let common: Common try { common = new CommonConstructor({ chain: customNetwork || chainId, ...commonOptions }) } catch (e: any) { if (e.message && /Chain.*not supported/.test(e.message)) { common = CommonConstructor.custom({ chainId }, commonOptions) } else { throw e } } return common } type StringifiedTransactionRequest = Omit< providers.TransactionRequest, | 'nonce' | 'gasLimit' | 'gasPrice' | 'value' | 'maxPriorityFeePerGas' | 'maxFeePerGas' > & { nonce: string gasLimit: string gasPrice?: string value: string maxPriorityFeePerGas?: string maxFeePerGas?: string } /** * Takes in TransactionRequest and converts all BigNumber values to strings * @param transaction * @returns a transaction where all BigNumber properties are now strings */ export const bigNumberFieldsToStrings = ( transaction: providers.TransactionRequest ): StringifiedTransactionRequest => Object.keys(transaction).reduce( (transaction, txnProperty) => ({ ...transaction, ...(( transaction[ txnProperty as keyof providers.TransactionRequest ] as BigNumber ).toHexString ? { [txnProperty]: ( transaction[ txnProperty as keyof providers.TransactionRequest ] as BigNumber ).toHexString() } : {}) }), transaction ) as StringifiedTransactionRequest /** * Helper method for hardware wallets to build an object * with a request method used for making rpc requests. * @param getRpcUrl - callback used to get the current chain's rpc url * @returns An object with a request method * to be called when making rpc requests */ export const getHardwareWalletProvider = ( getRpcUrl: () => string ): { request: EIP1193Provider['request'] } => ({ request: ({ method, params }) => fetch(getRpcUrl(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: '42', method, params }) }).then(async res => { const response = (await res.json()) as RPCResponse if ('error' in response) { throw response.error } return response.result }) })