Allow providers to detect their network after instantiation (#814).
This commit is contained in:
parent
0e3a66c829
commit
99ae946476
@ -175,6 +175,7 @@ let nextPollId = 1;
|
||||
|
||||
|
||||
export class BaseProvider extends Provider {
|
||||
_networkPromise: Promise<Network>;
|
||||
_network: Network;
|
||||
|
||||
_events: Array<Event>;
|
||||
@ -215,7 +216,6 @@ export class BaseProvider extends Provider {
|
||||
* MUST set this. Standard named networks have a known chainId.
|
||||
*
|
||||
*/
|
||||
ready: Promise<Network>;
|
||||
|
||||
constructor(network: Networkish | Promise<Network>) {
|
||||
logger.checkNew(new.target, Provider);
|
||||
@ -225,19 +225,15 @@ export class BaseProvider extends Provider {
|
||||
this.formatter = new.target.getFormatter();
|
||||
|
||||
if (network instanceof Promise) {
|
||||
defineReadOnly(this, "ready", network.then((network) => {
|
||||
defineReadOnly(this, "_network", network);
|
||||
return network;
|
||||
}));
|
||||
this._networkPromise = network;
|
||||
|
||||
// Squash any "unhandled promise" errors; that do not need to be handled
|
||||
this.ready.catch((error) => { });
|
||||
network.catch((error) => { });
|
||||
|
||||
} else {
|
||||
const knownNetwork = getStatic<(network: Networkish) => Network>(new.target, "getNetwork")(network);
|
||||
if (knownNetwork) {
|
||||
defineReadOnly(this, "_network", knownNetwork);
|
||||
defineReadOnly(this, "ready", Promise.resolve(this._network));
|
||||
|
||||
} else {
|
||||
logger.throwArgumentError("invalid network", "network", network);
|
||||
@ -258,6 +254,42 @@ export class BaseProvider extends Provider {
|
||||
this._fastQueryDate = 0;
|
||||
}
|
||||
|
||||
async _ready(): Promise<Network> {
|
||||
if (this._network == null) {
|
||||
let network: Network = null;
|
||||
if (this._networkPromise) {
|
||||
try {
|
||||
network = await this._networkPromise;
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
// Try the Provider's network detection (this MUST throw if it cannot)
|
||||
if (network == null) {
|
||||
network = await this.detectNetwork();
|
||||
}
|
||||
|
||||
// This should never happen; every Provider sub-class should have
|
||||
// suggested a network by here (or thrown).
|
||||
if (!network) {
|
||||
logger.throwError("no network detected", Logger.errors.UNKNOWN_ERROR, { });
|
||||
}
|
||||
|
||||
defineReadOnly(this, "_network", network);
|
||||
}
|
||||
|
||||
return this._network;
|
||||
}
|
||||
|
||||
get ready(): Promise<Network> {
|
||||
return this._ready();
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
return logger.throwError("provider does not support network detection", Logger.errors.UNSUPPORTED_OPERATION, {
|
||||
operation: "provider.detectNetwork"
|
||||
});
|
||||
}
|
||||
|
||||
static getFormatter(): Formatter {
|
||||
if (defaultFormatter == null) {
|
||||
defaultFormatter = new Formatter();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import { BlockTag, TransactionRequest, TransactionResponse } from "@ethersproject/abstract-provider";
|
||||
import { hexlify, hexValue } from "@ethersproject/bytes";
|
||||
import { Networkish } from "@ethersproject/networks";
|
||||
import { Network, Networkish } from "@ethersproject/networks";
|
||||
import { deepCopy, defineReadOnly } from "@ethersproject/properties";
|
||||
import { fetchJson } from "@ethersproject/web";
|
||||
|
||||
@ -109,6 +109,9 @@ export class EtherscanProvider extends BaseProvider{
|
||||
defineReadOnly(this, "apiKey", apiKey || defaultApiKey);
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
async perform(method: string, params: any): Promise<any> {
|
||||
let url = this.baseUrl;
|
||||
|
@ -379,14 +379,8 @@ export class FallbackProvider extends BaseProvider {
|
||||
const network = checkNetworks(providerConfigs.map((c) => (<any>(c.provider)).network));
|
||||
if (network) {
|
||||
super(network);
|
||||
|
||||
} else {
|
||||
// The network won't be known until all child providers know
|
||||
const ready = Promise.all(providerConfigs.map((c) => c.provider.getNetwork())).then((networks) => {
|
||||
return checkNetworks(networks);
|
||||
});
|
||||
|
||||
super(ready);
|
||||
super(this.detectNetwork());
|
||||
}
|
||||
|
||||
// Preserve a copy, so we do not get mutated
|
||||
@ -396,6 +390,11 @@ export class FallbackProvider extends BaseProvider {
|
||||
this._highestBlockNumber = -1;
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
const networks = await Promise.all(this.providerConfigs.map((c) => c.provider.getNetwork()));
|
||||
return checkNetworks(networks);
|
||||
}
|
||||
|
||||
async perform(method: string, params: { [name: string]: any }): Promise<any> {
|
||||
|
||||
// Sending transactions is special; always broadcast it to all backends
|
||||
|
@ -20,9 +20,7 @@ import { BaseProvider, Event } from "./base-provider";
|
||||
|
||||
function timer(timeout: number): Promise<any> {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(function() {
|
||||
resolve();
|
||||
}, timeout);
|
||||
setTimeout(resolve, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
@ -235,31 +233,9 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
if (network) {
|
||||
// The network has been specified explicitly, we can use it
|
||||
super(network);
|
||||
|
||||
} else {
|
||||
|
||||
// The network is unknown, query the JSON-RPC for it
|
||||
const ready: Promise<Network> = new Promise((resolve, reject) => {
|
||||
setTimeout(async () => {
|
||||
let chainId = null;
|
||||
try {
|
||||
chainId = await this.send("eth_chainId", [ ]);
|
||||
} catch (error) {
|
||||
try {
|
||||
chainId = await this.send("net_version", [ ]);
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (chainId != null) {
|
||||
try {
|
||||
return resolve(getNetwork(BigNumber.from(chainId).toNumber()));
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
reject(logger.makeError("could not detect network", Logger.errors.NETWORK_ERROR));
|
||||
}, 0);
|
||||
});
|
||||
super(ready);
|
||||
super(this.detectNetwork());
|
||||
}
|
||||
|
||||
// Default URL
|
||||
@ -280,6 +256,33 @@ export class JsonRpcProvider extends BaseProvider {
|
||||
return "http:/\/localhost:8545";
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
await timer(0);
|
||||
|
||||
let chainId = null;
|
||||
try {
|
||||
chainId = await this.send("eth_chainId", [ ]);
|
||||
} catch (error) {
|
||||
try {
|
||||
chainId = await this.send("net_version", [ ]);
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (chainId != null) {
|
||||
const getNetwork = getStatic<(network: Networkish) => Network>(this.constructor, "getNetwork");
|
||||
try {
|
||||
return getNetwork(BigNumber.from(chainId).toNumber());
|
||||
} catch (error) {
|
||||
return logger.throwError("could not detect network", Logger.errors.NETWORK_ERROR, {
|
||||
chainId: chainId,
|
||||
serverError: error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return logger.throwError("could not detect network", Logger.errors.NETWORK_ERROR);
|
||||
}
|
||||
|
||||
getSigner(addressOrIndex?: string | number): JsonRpcSigner {
|
||||
return new JsonRpcSigner(_constructorGuard, this, addressOrIndex);
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ export abstract class UrlJsonRpcProvider extends JsonRpcProvider {
|
||||
}
|
||||
}
|
||||
|
||||
async detectNetwork(): Promise<Network> {
|
||||
return this.network;
|
||||
}
|
||||
|
||||
_startPending(): void {
|
||||
logger.warn("WARNING: API provider does not support pending filters");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user