UNPKG

vue-blocklink

Version:

Vue support for the Blockchain Link browser extension

134 lines (131 loc) 6.17 kB
import { EIP1193Provider, JSONRPCErrorCallback, JSONRPCRequestPayload, JSONRPCResponsePayload, SupportedProvider, ZeroExProvider, } from '../types'; import * as _ from 'lodash'; export const providerUtils = { /** * Starts the Web3ProviderEngine without excess block polling * @param providerEngine The Web3ProviderEngine */ startProviderEngine(providerEngine: any): void { if (providerEngine.start === undefined) { throw new Error(`Invalid Web3ProviderEngine`); } // HACK: When calling start() Web3ProviderEngine starts a block polling service // this continuously pulls data from the network and can result in high data usage // for long running services. If used in a front end application this can cause // a high amount of load on a node (one request per user per block). providerEngine._ready.go(); providerEngine._running = true; }, /** * Standardize the supported provider types into our internal provider interface * or throw if unsupported provider supplied. * @param supportedProvider Potentially supported provider instance * @return Provider that conforms of our internal provider interface */ standardizeOrThrow(supportedProvider: SupportedProvider): ZeroExProvider { if (supportedProvider === undefined) { throw new Error(`supportedProvider cannot be 'undefined'`); } const provider = { isStandardizedProvider: true, isMetaMask: (supportedProvider as any).isMetaMask, isParity: (supportedProvider as any).isParity, stop: (supportedProvider as any).stop, enable: (supportedProvider as any).enable, sendAsync: _.noop.bind(_), // Will be replaced }; if (provider.enable) { // Need to bind, metamask can lose reference to function without binding as of 7.7.0 provider.enable.bind(supportedProvider); } // Case 1: We've already converted to our ZeroExProvider so noop. if ((supportedProvider as any).isStandardizedProvider) { // tslint:disable-next-line:no-unnecessary-type-assertion return supportedProvider as ZeroExProvider; // Case 2: It's a compliant EIP 1193 Provider // tslint:disable-next-line:no-unnecessary-type-assertion } else if ((supportedProvider as EIP1193Provider).isEIP1193) { provider.sendAsync = (payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback) => { const method = payload.method; const params = payload.params; (supportedProvider as any) .send(method, params) .then((result: any) => { callback(null, result); }) .catch((err: Error) => { callback(err); }); }; return provider; // Case 3: The provider has a `sendAsync` method, so we use it. } else if ((supportedProvider as any).sendAsync !== undefined) { provider.sendAsync = (supportedProvider as any).sendAsync.bind(supportedProvider); return provider; // Case 4: The provider does not have a `sendAsync` method but does have a `send` method } else if ((supportedProvider as any).send !== undefined) { // HACK(fabio): Detect if the `send` method has the old interface `send(payload, cb)` such // as in versions < Web3.js@1.0.0-beta.37. If so, do a simple re-mapping if (_.includes((supportedProvider as any).send.toString().replace(' ', ''), 'function(payload,callback)')) { provider.sendAsync = (supportedProvider as any).send.bind(supportedProvider); return provider; } else { // If doesn't have old interface, we assume it has new interface `send(method, payload)` // such as in versions > Web3.js@1.0.0-beta.38 and convert it to `sendAsync` provider.sendAsync = (payload: JSONRPCRequestPayload, callback: JSONRPCErrorCallback) => { const method = payload.method; const params = payload.params; (supportedProvider as any) .send(method, params) .then((result: any) => { callback(null, result); }) .catch((err: Error) => { callback(err); }); }; return provider; } } throw new Error( `Unsupported provider found. Please make sure it conforms to one of the supported providers. See 'Provider' type in 'ethereum-types' package.`, ); }, /** * Retrieve the chain ID from a supported provider. * @param supportedProvider A supported provider instance. * @return A promise that resolves to the chain ID of the network the provider * is connected to. */ async getChainIdAsync(supportedProvider: SupportedProvider): Promise<number> { const provider = providerUtils.standardizeOrThrow(supportedProvider); // tslint:disable-next-line:custom-no-magic-numbers const RPC_ID_MAX = 2 ** 64; return new Promise<number>((accept, reject) => { provider.sendAsync( { jsonrpc: '2.0', id: _.random(1, RPC_ID_MAX), method: 'eth_chainId', params: [], }, (err: Error | null, result?: JSONRPCResponsePayload) => { if (!_.isNil(err)) { reject(err); } if (!result) { throw new Error("Invalid 'eth_chainId' response"); } accept(_.toNumber(result.result)); }, ); }); }, };