From bffc557be1b84ae2b69edd5071f7a072c94421e9 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Tue, 20 Nov 2018 15:41:12 -0500 Subject: [PATCH] Added default provider support for Ethereum classic (#351). --- src.ts/ethers.ts | 7 +-- src.ts/providers/base-provider.ts | 20 +++++-- src.ts/providers/fallback-provider.ts | 3 +- src.ts/utils/networks.ts | 83 +++++++++++++++++++++------ 4 files changed, 84 insertions(+), 29 deletions(-) diff --git a/src.ts/ethers.ts b/src.ts/ethers.ts index 8f909bca8..6fe361e7a 100644 --- a/src.ts/ethers.ts +++ b/src.ts/ethers.ts @@ -33,10 +33,9 @@ import { ContractFunction, ContractTransaction, Event, EventFilter } from './con // Helper Functions function getDefaultProvider(network?: utils.Network | string): providers.BaseProvider { - return new providers.FallbackProvider([ - new providers.InfuraProvider(network), - new providers.EtherscanProvider(network), - ]); + let n = utils.getNetwork(network || 'homestead'); + if (!n || !n._defaultProvider) { return null; } + return n._defaultProvider(providers); } diff --git a/src.ts/providers/base-provider.ts b/src.ts/providers/base-provider.ts index 8d23f1a51..bb0e6351e 100644 --- a/src.ts/providers/base-provider.ts +++ b/src.ts/providers/base-provider.ts @@ -82,9 +82,13 @@ function arrayOf(check: CheckFunc): CheckFunc { }); } -function checkHash(hash: any): string { - if (typeof(hash) === 'string' && hexDataLength(hash) === 32) { - return hash.toLowerCase(); +function checkHash(hash: any, requirePrefix?: boolean): string { + if (typeof(hash) === 'string') { + // geth-etc does add a "0x" prefix on receipt.root + if (!requirePrefix && hash.substring(0, 2) !== '0x') { hash = '0x' + hash; } + if (hexDataLength(hash) === 32) { + return hash.toLowerCase(); + } } errors.throwError('invalid hash', errors.INVALID_ARGUMENT, { arg: 'hash', value: hash }); return null; @@ -220,11 +224,15 @@ function checkTransactionResponse(transaction: any): TransactionResponse { } } - let result = check(formatTransaction, transaction); let networkId = transaction.networkId; + // geth-etc returns chainId + if (transaction.chainId != null && networkId == null && result.v == null) { + networkId = transaction.chainId; + } + if (isHexString(networkId)) { networkId = bigNumberify(networkId).toNumber(); } @@ -979,7 +987,7 @@ export class BaseProvider extends Provider { getTransaction(transactionHash: string): Promise { return this.ready.then(() => { return resolveProperties({ transactionHash: transactionHash }).then(({ transactionHash }) => { - let params = { transactionHash: checkHash(transactionHash) }; + let params = { transactionHash: checkHash(transactionHash, true) }; return poll(() => { return this.perform('getTransaction', params).then((result) => { if (result == null) { @@ -1016,7 +1024,7 @@ export class BaseProvider extends Provider { getTransactionReceipt(transactionHash: string): Promise { return this.ready.then(() => { return resolveProperties({ transactionHash: transactionHash }).then(({ transactionHash }) => { - let params = { transactionHash: checkHash(transactionHash) }; + let params = { transactionHash: checkHash(transactionHash, true) }; return poll(() => { return this.perform('getTransactionReceipt', params).then((result) => { if (result == null) { diff --git a/src.ts/providers/fallback-provider.ts b/src.ts/providers/fallback-provider.ts index a5221ae07..43b992bd8 100644 --- a/src.ts/providers/fallback-provider.ts +++ b/src.ts/providers/fallback-provider.ts @@ -32,7 +32,8 @@ function checkNetworks(networks: Array): boolean { // Matches! if (check.name === network.name && check.chainId === network.chainId && - check.ensAddress === network.ensAddress) { return; } + ((check.ensAddress === network.ensAddress) || + (check.ensAddress == null && network.ensAddress == null))) { return; } errors.throwError( 'provider mismatch', diff --git a/src.ts/utils/networks.ts b/src.ts/utils/networks.ts index 390af96f7..8702243fa 100644 --- a/src.ts/utils/networks.ts +++ b/src.ts/utils/networks.ts @@ -7,33 +7,69 @@ export type Network = { name: string, chainId: number, ensAddress?: string, + _defaultProvider?: (providers: any) => any } export type Networkish = Network | string | number; +function ethDefaultProvider(network: string): (providers: any) => any { + return function(providers: any): any { + let providerList: Array = []; + + if (providers.InfuraProvider) { + providerList.push(new providers.InfuraProvider(network)); + } + + if (providers.EtherscanProvider) { + providerList.push(new providers.EtherscanProvider(network)); + } + + if (providerList.length === 0) { return null; } + + if (providers.FallbackProvider) { + return new providers.FallbackProvider(providerList);; + } + + return providerList[0]; + } +} + +function etcDefaultProvider(url: string, network: string): (providers: any) => any { + return function(providers: any): any { + if (providers.JsonRpcProvider) { + return new providers.JsonRpcProvider(url, network); + } + + return null; + } +} const homestead: Network = { chainId: 1, ensAddress: "0x314159265dd8dbb310642f98f50c066173c1259b", - name: "homestead" + name: "homestead", + _defaultProvider: ethDefaultProvider('homestead') }; const ropsten: Network = { chainId: 3, ensAddress: "0x112234455c3a32fd11230c42e7bccd4a84e02010", - name: "ropsten" + name: "ropsten", + _defaultProvider: ethDefaultProvider('ropsten') }; -const networks: { [name: string]: { chainId: number, ensAddress?: string } } = { +const networks: { [name: string]: Network } = { unspecified: { - chainId: 0 + chainId: 0, + name: 'unspecified' }, homestead: homestead, mainnet: homestead, morden: { - chainId: 2 + chainId: 2, + name: 'morden' }, ropsten: ropsten, @@ -41,19 +77,27 @@ const networks: { [name: string]: { chainId: number, ensAddress?: string } } = { rinkeby: { chainId: 4, - ensAddress: "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" + ensAddress: "0xe7410170f87102DF0055eB195163A03B7F2Bff4A", + name: 'rinkeby', + _defaultProvider: ethDefaultProvider('rinkeby') }, kovan: { - chainId: 42 + chainId: 42, + name: 'kovan', + _defaultProvider: ethDefaultProvider('kovan') }, classic: { - chainId: 61 + chainId: 61, + name: 'classic', + _defaultProvider: etcDefaultProvider('https://web3.gastracker.io', 'classic') }, classicTestnet: { - chainId: 62 + chainId: 62, + name: 'classicTestnet', + _defaultProvider: etcDefaultProvider('https://web3.gastracker.io/morden', 'classicTestnet') } } @@ -64,17 +108,18 @@ const networks: { [name: string]: { chainId: number, ensAddress?: string } } = { * and verifies a network is a valid Network.. */ export function getNetwork(network: Networkish): Network { - // No network (null) or unspecified (chainId = 0) - if (!network) { return null; } + // No network (null) + if (network == null) { return null; } if (typeof(network) === 'number') { - for (var name in networks) { + for (let name in networks) { let n = networks[name]; if (n.chainId === network) { return { - name: name, + name: n.name, chainId: n.chainId, - ensAddress: n.ensAddress + ensAddress: (n.ensAddress || null), + _defaultProvider: (n._defaultProvider || null) }; } } @@ -89,9 +134,10 @@ export function getNetwork(network: Networkish): Network { let n = networks[network]; if (n == null) { return null; } return { - name: network, + name: n.name, chainId: n.chainId, - ensAddress: n.ensAddress + ensAddress: n.ensAddress, + _defaultProvider: (n._defaultProvider || null) }; } @@ -110,10 +156,11 @@ export function getNetwork(network: Networkish): Network { errors.throwError('network chainId mismatch', errors.INVALID_ARGUMENT, { arg: 'network', value: network }); } - // Standard Network + // Standard Network (allow overriding the ENS address) return { name: network.name, chainId: n.chainId, - ensAddress: n.ensAddress + ensAddress: (network.ensAddress || n.ensAddress || null), + _defaultProvider: (network._defaultProvider || n._defaultProvider || null) }; }