aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfragosti <francesco.agosti93@gmail.com>2018-11-02 06:01:05 +0800
committerfragosti <francesco.agosti93@gmail.com>2018-11-02 06:01:05 +0800
commit32de4862ba94223258f7a08da6373313c9e28f8b (patch)
treeae9598e85afa7ea5bb5ee819f987cab3cff72ceb
parent8c336925601127c759ad4cfbca119368a2edfd56 (diff)
parent0955feb0234bc90b7dcf5ad3a308570c9fa5d490 (diff)
downloaddexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar.gz
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar.bz2
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar.lz
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar.xz
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.tar.zst
dexon-sol-tools-32de4862ba94223258f7a08da6373313c9e28f8b.zip
Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/instant/token-selection-panel
-rw-r--r--packages/asset-buyer/CHANGELOG.json4
-rw-r--r--packages/asset-buyer/src/asset_buyer.ts1
-rw-r--r--packages/asset-buyer/src/utils/assert.ts16
-rw-r--r--packages/instant/public/index.html57
-rw-r--r--packages/instant/src/data/asset_data_network_mapping.ts5
-rw-r--r--packages/instant/src/data/asset_meta_data_map.ts6
-rw-r--r--packages/website/ts/blockchain.ts127
-rw-r--r--packages/website/ts/types.ts8
8 files changed, 118 insertions, 106 deletions
diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json
index c572ba4cf..6ba2a0fd9 100644
--- a/packages/asset-buyer/CHANGELOG.json
+++ b/packages/asset-buyer/CHANGELOG.json
@@ -10,6 +10,10 @@
"note":
"the `OrderProvider` now requires a new method `getAvailableMakerAssetDatasAsync` and the `StandardRelayerAPIOrderProvider` requires the network id at init.",
"pr": 1203
+ },
+ {
+ "note": "No longer require that provided orders all have the same maker and taker asset data",
+ "pr": 1197
}
]
},
diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts
index 2bc80ac12..49743404f 100644
--- a/packages/asset-buyer/src/asset_buyer.ts
+++ b/packages/asset-buyer/src/asset_buyer.ts
@@ -56,7 +56,6 @@ export class AssetBuyer {
): AssetBuyer {
assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
- assert.areValidProvidedOrders('orders', orders);
assert.assert(orders.length !== 0, `Expected orders to contain at least one order`);
const orderProvider = new BasicOrderProvider(orders);
const assetBuyer = new AssetBuyer(provider, orderProvider, options);
diff --git a/packages/asset-buyer/src/utils/assert.ts b/packages/asset-buyer/src/utils/assert.ts
index e5bfd2d81..2466f53a4 100644
--- a/packages/asset-buyer/src/utils/assert.ts
+++ b/packages/asset-buyer/src/utils/assert.ts
@@ -1,6 +1,5 @@
import { assert as sharedAssert } from '@0x/assert';
import { schemas } from '@0x/json-schemas';
-import { SignedOrder } from '@0x/types';
import * as _ from 'lodash';
import { BuyQuote, BuyQuoteInfo, OrderProvider, OrderProviderRequest } from '../types';
@@ -30,21 +29,6 @@ export const assert = {
sharedAssert.isHexString(`${variableName}.makerAssetData`, orderFetcherRequest.makerAssetData);
sharedAssert.isHexString(`${variableName}.takerAssetData`, orderFetcherRequest.takerAssetData);
},
- areValidProvidedOrders(variableName: string, orders: SignedOrder[]): void {
- if (orders.length === 0) {
- return;
- }
- const makerAssetData = orders[0].makerAssetData;
- const takerAssetData = orders[0].takerAssetData;
- const filteredOrders = _.filter(
- orders,
- order => order.makerAssetData === makerAssetData && order.takerAssetData === takerAssetData,
- );
- sharedAssert.assert(
- orders.length === filteredOrders.length,
- `Expected all orders in ${variableName} to have the same makerAssetData and takerAssetData.`,
- );
- },
isValidPercentage(variableName: string, percentage: number): void {
assert.isNumber(variableName, percentage);
assert.assert(
diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html
index 9f1dfdb64..62532dad9 100644
--- a/packages/instant/public/index.html
+++ b/packages/instant/public/index.html
@@ -34,25 +34,42 @@
EXPONENTIAL_AT: 1000,
DECIMAL_PLACES: 78,
});
- const providedOrder = {
- senderAddress: '0x0000000000000000000000000000000000000000',
- makerAddress: '0x14e2f1f157e7dd4057d02817436d628a37120fd1',
- takerAddress: '0x0000000000000000000000000000000000000000',
- makerFee: new BigNumber('0'),
- takerFee: new BigNumber('0'),
- makerAssetAmount: new BigNumber('100000000000000000000'),
- takerAssetAmount: new BigNumber('10000000000000000'),
- makerAssetData: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
- takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
- expirationTimeSeconds: new BigNumber('1591858800'),
- feeRecipientAddress: '0x0000000000000000000000000000000000000000',
- salt: new BigNumber(
- '54983920541892966634674340965984367456810207583416050222519063020710969340046',
- ),
- signature:
- '0x1b949656218421c845995457303569a656764afa2b979d41dcefff0009d57ce15001490268bc7caa4269894fd83b741465fc5a7a53eda6ece17eb91fb32655d83703',
- exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
- };
+ const providedOrders = [
+ // Order selling REP
+ {
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ makerFee: new BigNumber('0'),
+ takerFee: new BigNumber('0'),
+ makerAssetAmount: new BigNumber('400000000000000000000'),
+ takerAssetAmount: new BigNumber('40000000000000000000'),
+ makerAssetData: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c',
+ takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
+ expirationTimeSeconds: new BigNumber('1543046400'),
+ feeRecipientAddress: '0x0000000000000000000000000000000000000000',
+ salt: new BigNumber('47929252863126413473766089649682650973189811771354566206928245255479607883031'),
+ signature: '0x1c0bf8ba709ceb5b32e6b0b5a8bb7f07e9d19aba88d8530715f8a298d12188e3862fcc0a30ddfad4062b30459f2859323c064052f12cc687466c457934b9419a1b03',
+ exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
+ },
+ // Order selling ZRX
+ {
+ senderAddress: '0x0000000000000000000000000000000000000000',
+ makerAddress: '0x34a745008a643eebc58920eaa29fb1165b4a288e',
+ takerAddress: '0x0000000000000000000000000000000000000000',
+ makerFee: new BigNumber('0'),
+ takerFee: new BigNumber('0'),
+ makerAssetAmount: new BigNumber('300000000000000000000'),
+ takerAssetAmount: new BigNumber('31000000000000000000'),
+ makerAssetData: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa',
+ takerAssetData: '0xf47261b0000000000000000000000000d0a1e359811322d97991e03f863a0c30c2cf029c',
+ expirationTimeSeconds: new BigNumber('2524636800'),
+ feeRecipientAddress: '0x0000000000000000000000000000000000000000',
+ salt: new BigNumber('64592004666704945574675477805199411288137454783320798602050822322450089238268'),
+ signature: '0x1c13cacddca8d7d8248e91f412377e68f8f1f9891a59a6c1b2eea9f7b33558c30c4fb86a448e08ab7def40a28fb3a3062dcb33bb3c45302447fce5c4288b7c7f5b03',
+ exchangeAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2'
+ }
+ ];
const queryParams = new Uri(window.location.search);
const renderOptionsDefaults = {
liquiditySource: 'https://api.radarrelay.com/0x/v2/',
@@ -60,7 +77,7 @@
}
const liquiditySourceOverride = queryParams.getQueryParamValue('liquiditySource');
const renderOptionsOverrides = {
- liquiditySource: liquiditySourceOverride === 'provided' ? [providedOrder] : liquiditySourceOverride,
+ liquiditySource: liquiditySourceOverride === 'provided' ? providedOrders : liquiditySourceOverride,
assetData: queryParams.getQueryParamValue('assetData'),
networkId: +queryParams.getQueryParamValue('networkId') || undefined,
defaultAssetBuyAmount: +queryParams.getQueryParamValue('defaultAssetBuyAmount') || undefined,
diff --git a/packages/instant/src/data/asset_data_network_mapping.ts b/packages/instant/src/data/asset_data_network_mapping.ts
index 45bfc2a02..a7bc6a967 100644
--- a/packages/instant/src/data/asset_data_network_mapping.ts
+++ b/packages/instant/src/data/asset_data_network_mapping.ts
@@ -56,4 +56,9 @@ export const assetDataNetworkMapping: AssetDataByNetwork[] = [
{
[Network.Mainnet]: '0xf47261b000000000000000000000000008d32b0da63e2C3bcF8019c9c5d849d7a9d791e6',
},
+ // REP
+ {
+ [Network.Kovan]: '0xf47261b00000000000000000000000008cb3971b8eb709c14616bd556ff6683019e90d9c',
+ [Network.Mainnet]: '0xf47261b0000000000000000000000000e94327d07fc17907b4db788e5adf2ed424addff6',
+ },
];
diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts
index d77298d78..d7cf2c0d8 100644
--- a/packages/instant/src/data/asset_meta_data_map.ts
+++ b/packages/instant/src/data/asset_meta_data_map.ts
@@ -65,4 +65,10 @@ export const assetMetaDataMap: ObjectMap<AssetMetaData> = {
primaryColor: '#000',
symbol: 'dentacoin',
},
+ '0xf47261b0000000000000000000000000e94327d07fc17907b4db788e5adf2ed424addff6': {
+ assetProxyId: AssetProxyId.ERC20,
+ decimals: 18,
+ primaryColor: '#512D80',
+ symbol: 'rep',
+ },
};
diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts
index 62e16dd1d..b43c41739 100644
--- a/packages/website/ts/blockchain.ts
+++ b/packages/website/ts/blockchain.ts
@@ -20,7 +20,7 @@ import {
Web3ProviderEngine,
} from '@0x/subproviders';
import { SignedOrder, Token as ZeroExToken } from '@0x/types';
-import { BigNumber, intervalUtils, logUtils, promisify } from '@0x/utils';
+import { BigNumber, intervalUtils, logUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { BlockParam, LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -38,9 +38,9 @@ import {
BlockchainErrs,
ContractInstance,
Fill,
+ InjectedProvider,
InjectedProviderObservable,
InjectedProviderUpdate,
- InjectedWeb3,
Providers,
ProviderType,
Side,
@@ -83,6 +83,7 @@ export class Blockchain {
private _ledgerSubprovider: LedgerSubprovider;
private _defaultGasPrice: BigNumber;
private _watchGasPriceIntervalId: NodeJS.Timer;
+ private _injectedProviderIfExists?: InjectedProvider;
private static _getNameGivenProvider(provider: Provider): string {
const providerType = utils.getProviderType(provider);
const providerNameIfExists = providerToName[providerType];
@@ -91,48 +92,12 @@ export class Blockchain {
}
return providerNameIfExists;
}
- private static _getInjectedWeb3(): InjectedWeb3 {
- const injectedWeb3IfExists = (window as any).web3;
- // Our core assumptions about the injected web3 object is that it has the following
- // properties and methods.
- if (
- _.isUndefined(injectedWeb3IfExists) ||
- _.isUndefined(injectedWeb3IfExists.version) ||
- _.isUndefined(injectedWeb3IfExists.version.getNetwork) ||
- _.isUndefined(injectedWeb3IfExists.currentProvider)
- ) {
- return undefined;
- }
- return injectedWeb3IfExists;
- }
- private static async _getInjectedWeb3ProviderNetworkIdIfExistsAsync(): Promise<number | undefined> {
- // Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in
- // order to properly instantiate the web3Wrapper. Since we must use the async call, we cannot
- // retrieve it from within the web3Wrapper constructor. This is and should remain the only
- // call to a web3 instance outside of web3Wrapper in the entire dapp.
- // In addition, if the user has an injectedWeb3 instance that is disconnected from a backing
- // Ethereum node, this call will throw. We need to handle this case gracefully
- const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
- let networkIdIfExists: number;
- if (!_.isUndefined(injectedWeb3IfExists)) {
- try {
- networkIdIfExists = _.parseInt(
- await promisify<string>(
- injectedWeb3IfExists.version.getNetwork.bind(injectedWeb3IfExists.version),
- )(),
- );
- } catch (err) {
- // Ignore error and proceed with networkId undefined
- }
- }
- return networkIdIfExists;
- }
private static async _getProviderAsync(
- injectedWeb3: InjectedWeb3,
- networkIdIfExists: number,
+ injectedProviderIfExists?: InjectedProvider,
+ networkIdIfExists?: number,
shouldUserLedgerProvider: boolean = false,
): Promise<[Provider, LedgerSubprovider | undefined]> {
- const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3);
+ const doesInjectedProviderExist = !_.isUndefined(injectedProviderIfExists);
const isNetworkIdAvailable = !_.isUndefined(networkIdIfExists);
const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists];
const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId);
@@ -156,16 +121,16 @@ export class Blockchain {
provider.addProvider(new RedundantSubprovider(rpcSubproviders));
provider.start();
return [provider, ledgerSubprovider];
- } else if (doesInjectedWeb3Exist && isPublicNodeAvailableForNetworkId) {
+ } else if (doesInjectedProviderExist && isPublicNodeAvailableForNetworkId) {
// We catch all requests involving a users account and send it to the injectedWeb3
// instance. All other requests go to the public hosted node.
const provider = new Web3ProviderEngine();
- const providerName = this._getNameGivenProvider(injectedWeb3.currentProvider);
+ const providerName = this._getNameGivenProvider(injectedProviderIfExists);
// Wrap Metamask in a compatability wrapper MetamaskSubprovider (to handle inconsistencies)
const signerSubprovider =
providerName === constants.PROVIDER_NAME_METAMASK
- ? new MetamaskSubprovider(injectedWeb3.currentProvider)
- : new SignerSubprovider(injectedWeb3.currentProvider);
+ ? new MetamaskSubprovider(injectedProviderIfExists)
+ : new SignerSubprovider(injectedProviderIfExists);
provider.addProvider(signerSubprovider);
provider.addProvider(new FilterSubprovider());
const rpcSubproviders = _.map(publicNodeUrlsIfExistsForNetworkId, publicNodeUrl => {
@@ -174,9 +139,9 @@ export class Blockchain {
provider.addProvider(new RedundantSubprovider(rpcSubproviders));
provider.start();
return [provider, undefined];
- } else if (doesInjectedWeb3Exist) {
+ } else if (doesInjectedProviderExist) {
// Since no public node for this network, all requests go to injectedWeb3 instance
- return [injectedWeb3.currentProvider, undefined];
+ return [injectedProviderIfExists, undefined];
} else {
// If no injectedWeb3 instance, all requests fallback to our public hosted mainnet/testnet node
// We do this so that users can still browse the 0x Portal DApp even if they do not have web3
@@ -261,7 +226,7 @@ export class Blockchain {
const shouldUserLedgerProvider = false;
this._dispatcher.updateBlockchainIsLoaded(false);
// We don't want to be out of sync with the network the injected provider declares.
- const networkId = await Blockchain._getInjectedWeb3ProviderNetworkIdIfExistsAsync();
+ const networkId = await this._getInjectedProviderNetworkIdIfExistsAsync();
await this._resetOrInitializeAsync(networkId, shouldPollUserAddress, shouldUserLedgerProvider);
}
public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> {
@@ -611,6 +576,45 @@ export class Blockchain {
this._dispatcher.updateBlockchainIsLoaded(true);
}
+ private async _getInjectedProviderIfExistsAsync(): Promise<InjectedProvider | undefined> {
+ if (!_.isUndefined(this._injectedProviderIfExists)) {
+ return this._injectedProviderIfExists;
+ }
+ let injectedProviderIfExists = (window as any).ethereum;
+ if (!_.isUndefined(injectedProviderIfExists)) {
+ if (!_.isUndefined(injectedProviderIfExists.enable)) {
+ try {
+ await injectedProviderIfExists.enable();
+ } catch (err) {
+ errorReporter.report(err);
+ }
+ }
+ } else {
+ const injectedWeb3IfExists = (window as any).web3;
+ if (!_.isUndefined(injectedWeb3IfExists.currentProvider)) {
+ injectedProviderIfExists = injectedWeb3IfExists.currentProvider;
+ } else {
+ return undefined;
+ }
+ }
+ this._injectedProviderIfExists = injectedProviderIfExists;
+ return injectedProviderIfExists;
+ }
+ private async _getInjectedProviderNetworkIdIfExistsAsync(): Promise<number | undefined> {
+ // If the user has an injectedWeb3 instance that is disconnected from a backing
+ // Ethereum node, this call will throw. We need to handle this case gracefully
+ const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync();
+ let networkIdIfExists: number;
+ if (!_.isUndefined(injectedProviderIfExists)) {
+ try {
+ const injectedWeb3Wrapper = new Web3Wrapper(injectedProviderIfExists);
+ networkIdIfExists = await injectedWeb3Wrapper.getNetworkIdAsync();
+ } catch (err) {
+ // Ignore error and proceed with networkId undefined
+ }
+ }
+ return networkIdIfExists;
+ }
private async _showEtherScanLinkAndAwaitTransactionMinedAsync(
txHash: string,
): Promise<TransactionReceiptWithDecodedLogs> {
@@ -804,17 +808,17 @@ export class Blockchain {
}
private async _onPageLoadInitFireAndForgetAsync(): Promise<void> {
await utils.onPageLoadPromise; // wait for page to load
- const networkIdIfExists = await Blockchain._getInjectedWeb3ProviderNetworkIdIfExistsAsync();
+ const networkIdIfExists = await this._getInjectedProviderNetworkIdIfExistsAsync();
this.networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : constants.NETWORK_ID_MAINNET;
- const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
- if (!_.isUndefined(injectedWeb3IfExists) && !_.isUndefined(injectedWeb3IfExists.currentProvider)) {
- const injectedProviderObservable = injectedWeb3IfExists.currentProvider.publicConfigStore;
+ const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync();
+ if (!_.isUndefined(injectedProviderIfExists)) {
+ const injectedProviderObservable = injectedProviderIfExists.publicConfigStore;
if (!_.isUndefined(injectedProviderObservable) && _.isUndefined(this._injectedProviderObservable)) {
this._injectedProviderObservable = injectedProviderObservable;
this._injectedProviderObservable.subscribe(this._injectedProviderUpdateHandler);
}
}
- this._updateProviderName(injectedWeb3IfExists);
+ this._updateProviderName(injectedProviderIfExists);
const shouldPollUserAddress = true;
const shouldUseLedgerProvider = false;
this._startWatchingGasPrice();
@@ -851,12 +855,14 @@ export class Blockchain {
}
this._dispatcher.updateUserWeiBalance(undefined);
this.networkId = networkId;
- const injectedWeb3IfExists = Blockchain._getInjectedWeb3();
+ const injectedProviderIfExists = await this._getInjectedProviderIfExistsAsync();
const [provider, ledgerSubproviderIfExists] = await Blockchain._getProviderAsync(
- injectedWeb3IfExists,
+ injectedProviderIfExists,
networkId,
shouldUserLedgerProvider,
);
+ this._web3Wrapper = new Web3Wrapper(provider);
+ this.networkId = await this._web3Wrapper.getNetworkIdAsync();
if (!_.isUndefined(this._contractWrappers)) {
this._contractWrappers.unsubscribeAll();
}
@@ -867,7 +873,6 @@ export class Blockchain {
if (!_.isUndefined(this._blockchainWatcher)) {
this._blockchainWatcher.destroy();
}
- this._web3Wrapper = new Web3Wrapper(provider);
this._blockchainWatcher = new BlockchainWatcher(this._dispatcher, this._web3Wrapper, shouldPollUserAddress);
if (shouldUserLedgerProvider && !_.isUndefined(ledgerSubproviderIfExists)) {
delete this._userAddressIfExists;
@@ -879,7 +884,7 @@ export class Blockchain {
const userAddresses = await this._web3Wrapper.getAvailableAddressesAsync();
this._userAddressIfExists = userAddresses[0];
this._dispatcher.updateUserAddress(this._userAddressIfExists);
- if (!_.isUndefined(injectedWeb3IfExists)) {
+ if (!_.isUndefined(injectedProviderIfExists)) {
this._dispatcher.updateProviderType(ProviderType.Injected);
}
await this.fetchTokenInformationAsync();
@@ -888,10 +893,10 @@ export class Blockchain {
this._dispatcher.updateNetworkId(networkId);
await this._rehydrateStoreWithContractEventsAsync();
}
- private _updateProviderName(injectedWeb3IfExists: InjectedWeb3): void {
- const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3IfExists);
- const providerName = doesInjectedWeb3Exist
- ? Blockchain._getNameGivenProvider(injectedWeb3IfExists.currentProvider)
+ private _updateProviderName(injectedProviderIfExists?: InjectedProvider): void {
+ const doesInjectedProviderExist = !_.isUndefined(injectedProviderIfExists);
+ const providerName = doesInjectedProviderExist
+ ? Blockchain._getNameGivenProvider(injectedProviderIfExists)
: constants.PROVIDER_NAME_PUBLIC;
this._dispatcher.updateInjectedProviderName(providerName);
}
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 22bfd2cb4..ce4b50a58 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -616,14 +616,6 @@ export interface InjectedProvider extends Provider {
publicConfigStore?: InjectedProviderObservable;
}
-// Minimal expected interface for an injected web3 object
-export interface InjectedWeb3 {
- currentProvider: InjectedProvider;
- version: {
- getNetwork(cd: (err: Error, networkId: string) => void): void;
- };
-}
-
export interface TutorialInfo {
iconUrl: string;
description: string;