diff options
-rw-r--r-- | packages/asset-buyer/CHANGELOG.json | 4 | ||||
-rw-r--r-- | packages/asset-buyer/src/asset_buyer.ts | 1 | ||||
-rw-r--r-- | packages/asset-buyer/src/utils/assert.ts | 16 | ||||
-rw-r--r-- | packages/instant/public/index.html | 57 | ||||
-rw-r--r-- | packages/instant/src/data/asset_data_network_mapping.ts | 5 | ||||
-rw-r--r-- | packages/instant/src/data/asset_meta_data_map.ts | 6 | ||||
-rw-r--r-- | packages/website/ts/blockchain.ts | 127 | ||||
-rw-r--r-- | packages/website/ts/types.ts | 8 |
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; |